aboutsummaryrefslogtreecommitdiffstats
path: root/libusb-1.0/libusb
diff options
context:
space:
mode:
Diffstat (limited to 'libusb-1.0/libusb')
-rw-r--r--libusb-1.0/libusb/.DS_Storebin0 -> 12292 bytes
-rw-r--r--libusb-1.0/libusb/._.DS_Storebin0 -> 4096 bytes
-rw-r--r--libusb-1.0/libusb/.deps/libusb_1_0_la-core.Plo1
-rw-r--r--libusb-1.0/libusb/.deps/libusb_1_0_la-darwin_usb.Plo1
-rw-r--r--libusb-1.0/libusb/.deps/libusb_1_0_la-descriptor.Plo1
-rw-r--r--libusb-1.0/libusb/.deps/libusb_1_0_la-io.Plo1
-rw-r--r--libusb-1.0/libusb/.deps/libusb_1_0_la-linux_usbfs.Plo1
-rw-r--r--libusb-1.0/libusb/.deps/libusb_1_0_la-poll_windows.Plo1
-rw-r--r--libusb-1.0/libusb/.deps/libusb_1_0_la-sync.Plo1
-rw-r--r--libusb-1.0/libusb/.deps/libusb_1_0_la-threads_windows.Plo1
-rw-r--r--libusb-1.0/libusb/.deps/libusb_1_0_la-windows_usb.Plo1
-rw-r--r--libusb-1.0/libusb/Makefile701
-rw-r--r--libusb-1.0/libusb/Makefile.am44
-rw-r--r--libusb-1.0/libusb/Makefile.in701
-rw-r--r--libusb-1.0/libusb/core.c1738
-rw-r--r--libusb-1.0/libusb/descriptor.c721
-rw-r--r--libusb-1.0/libusb/io.c2366
-rw-r--r--libusb-1.0/libusb/libusb-1.0.def572
-rw-r--r--libusb-1.0/libusb/libusb-1.0.rc50
-rw-r--r--libusb-1.0/libusb/libusb.h1353
-rw-r--r--libusb-1.0/libusb/libusb_version.h29
-rw-r--r--libusb-1.0/libusb/libusb_version.h.in29
-rw-r--r--libusb-1.0/libusb/libusbi.h873
-rw-r--r--libusb-1.0/libusb/os/.DS_Storebin0 -> 6148 bytes
-rw-r--r--libusb-1.0/libusb/os/._.DS_Storebin0 -> 4096 bytes
-rw-r--r--libusb-1.0/libusb/os/darwin_usb.c1545
-rw-r--r--libusb-1.0/libusb/os/darwin_usb.h167
-rw-r--r--libusb-1.0/libusb/os/linux_usbfs.c2220
-rw-r--r--libusb-1.0/libusb/os/linux_usbfs.h138
-rw-r--r--libusb-1.0/libusb/os/poll_posix.h12
-rw-r--r--libusb-1.0/libusb/os/poll_windows.c857
-rw-r--r--libusb-1.0/libusb/os/poll_windows.h122
-rw-r--r--libusb-1.0/libusb/os/threads_posix.h46
-rw-r--r--libusb-1.0/libusb/os/threads_windows.c221
-rw-r--r--libusb-1.0/libusb/os/threads_windows.h84
-rw-r--r--libusb-1.0/libusb/os/windows_usb.c4226
-rw-r--r--libusb-1.0/libusb/os/windows_usb.h784
-rw-r--r--libusb-1.0/libusb/sync.c310
38 files changed, 19918 insertions, 0 deletions
diff --git a/libusb-1.0/libusb/.DS_Store b/libusb-1.0/libusb/.DS_Store
new file mode 100644
index 0000000..12aed82
--- /dev/null
+++ b/libusb-1.0/libusb/.DS_Store
Binary files differ
diff --git a/libusb-1.0/libusb/._.DS_Store b/libusb-1.0/libusb/._.DS_Store
new file mode 100644
index 0000000..338bd7b
--- /dev/null
+++ b/libusb-1.0/libusb/._.DS_Store
Binary files differ
diff --git a/libusb-1.0/libusb/.deps/libusb_1_0_la-core.Plo b/libusb-1.0/libusb/.deps/libusb_1_0_la-core.Plo
new file mode 100644
index 0000000..9ce06a8
--- /dev/null
+++ b/libusb-1.0/libusb/.deps/libusb_1_0_la-core.Plo
@@ -0,0 +1 @@
+# dummy
diff --git a/libusb-1.0/libusb/.deps/libusb_1_0_la-darwin_usb.Plo b/libusb-1.0/libusb/.deps/libusb_1_0_la-darwin_usb.Plo
new file mode 100644
index 0000000..9ce06a8
--- /dev/null
+++ b/libusb-1.0/libusb/.deps/libusb_1_0_la-darwin_usb.Plo
@@ -0,0 +1 @@
+# dummy
diff --git a/libusb-1.0/libusb/.deps/libusb_1_0_la-descriptor.Plo b/libusb-1.0/libusb/.deps/libusb_1_0_la-descriptor.Plo
new file mode 100644
index 0000000..9ce06a8
--- /dev/null
+++ b/libusb-1.0/libusb/.deps/libusb_1_0_la-descriptor.Plo
@@ -0,0 +1 @@
+# dummy
diff --git a/libusb-1.0/libusb/.deps/libusb_1_0_la-io.Plo b/libusb-1.0/libusb/.deps/libusb_1_0_la-io.Plo
new file mode 100644
index 0000000..9ce06a8
--- /dev/null
+++ b/libusb-1.0/libusb/.deps/libusb_1_0_la-io.Plo
@@ -0,0 +1 @@
+# dummy
diff --git a/libusb-1.0/libusb/.deps/libusb_1_0_la-linux_usbfs.Plo b/libusb-1.0/libusb/.deps/libusb_1_0_la-linux_usbfs.Plo
new file mode 100644
index 0000000..9ce06a8
--- /dev/null
+++ b/libusb-1.0/libusb/.deps/libusb_1_0_la-linux_usbfs.Plo
@@ -0,0 +1 @@
+# dummy
diff --git a/libusb-1.0/libusb/.deps/libusb_1_0_la-poll_windows.Plo b/libusb-1.0/libusb/.deps/libusb_1_0_la-poll_windows.Plo
new file mode 100644
index 0000000..9ce06a8
--- /dev/null
+++ b/libusb-1.0/libusb/.deps/libusb_1_0_la-poll_windows.Plo
@@ -0,0 +1 @@
+# dummy
diff --git a/libusb-1.0/libusb/.deps/libusb_1_0_la-sync.Plo b/libusb-1.0/libusb/.deps/libusb_1_0_la-sync.Plo
new file mode 100644
index 0000000..9ce06a8
--- /dev/null
+++ b/libusb-1.0/libusb/.deps/libusb_1_0_la-sync.Plo
@@ -0,0 +1 @@
+# dummy
diff --git a/libusb-1.0/libusb/.deps/libusb_1_0_la-threads_windows.Plo b/libusb-1.0/libusb/.deps/libusb_1_0_la-threads_windows.Plo
new file mode 100644
index 0000000..9ce06a8
--- /dev/null
+++ b/libusb-1.0/libusb/.deps/libusb_1_0_la-threads_windows.Plo
@@ -0,0 +1 @@
+# dummy
diff --git a/libusb-1.0/libusb/.deps/libusb_1_0_la-windows_usb.Plo b/libusb-1.0/libusb/.deps/libusb_1_0_la-windows_usb.Plo
new file mode 100644
index 0000000..9ce06a8
--- /dev/null
+++ b/libusb-1.0/libusb/.deps/libusb_1_0_la-windows_usb.Plo
@@ -0,0 +1 @@
+# dummy
diff --git a/libusb-1.0/libusb/Makefile b/libusb-1.0/libusb/Makefile
new file mode 100644
index 0000000..234235e
--- /dev/null
+++ b/libusb-1.0/libusb/Makefile
@@ -0,0 +1,701 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# libusb/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+
+pkgdatadir = $(datadir)/libusb
+pkgincludedir = $(includedir)/libusb
+pkglibdir = $(libdir)/libusb
+pkglibexecdir = $(libexecdir)/libusb
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = i386-apple-darwin10.0.0
+host_triplet = i386-apple-darwin10.0.0
+##am__append_1 = os/threads_windows.c
+subdir = libusb
+DIST_COMMON = $(hdr_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/libusb_version.h.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = libusb_version.h
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(hdrdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libusb_1_0_la_LIBADD =
+am__libusb_1_0_la_SOURCES_DIST = libusbi.h core.c descriptor.c io.c \
+ sync.c os/darwin_usb.c os/threads_windows.c os/linux_usbfs.c \
+ os/poll_windows.c os/windows_usb.c libusb-1.0.rc \
+ os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h \
+ os/threads_posix.h os/threads_windows.h os/poll_posix.h \
+ os/poll_windows.h
+am__objects_1 = libusb_1_0_la-darwin_usb.lo
+##am__objects_2 = libusb_1_0_la-threads_windows.lo
+am__objects_3 = libusb_1_0_la-linux_usbfs.lo
+am__objects_4 = libusb_1_0_la-poll_windows.lo \
+ libusb_1_0_la-windows_usb.lo libusb-1.0.lo
+##am__objects_5 = $(am__objects_4) \
+## $(am__objects_2)
+##am__objects_5 = $(am__objects_3) \
+## $(am__objects_2)
+am__objects_5 = $(am__objects_1) $(am__objects_2)
+am_libusb_1_0_la_OBJECTS = libusb_1_0_la-core.lo \
+ libusb_1_0_la-descriptor.lo libusb_1_0_la-io.lo \
+ libusb_1_0_la-sync.lo $(am__objects_5)
+libusb_1_0_la_OBJECTS = $(am_libusb_1_0_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+libusb_1_0_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libusb_1_0_la_CFLAGS) \
+ $(CFLAGS) $(libusb_1_0_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I. -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libusb_1_0_la_SOURCES)
+DIST_SOURCES = $(am__libusb_1_0_la_SOURCES_DIST)
+HEADERS = $(hdr_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /Users/Ben/Desktop/heimdall-1.1.0/libusb-1.0/missing --run aclocal-1.11
+AMTAR = ${SHELL} /Users/Ben/Desktop/heimdall-1.1.0/libusb-1.0/missing --run tar
+AM_CFLAGS = -std=gnu99 -fgnu89-inline -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration -Wno-pointer-sign -Wshadow
+AM_DEFAULT_VERBOSITY = 0
+AM_LDFLAGS = -Wl,-framework,IOKit -Wl,-framework,CoreFoundation -Wl,-prebind -no-undefined -pthread
+AR = ar
+AUTOCONF = ${SHELL} /Users/Ben/Desktop/heimdall-1.1.0/libusb-1.0/missing --run autoconf
+AUTOHEADER = ${SHELL} /Users/Ben/Desktop/heimdall-1.1.0/libusb-1.0/missing --run autoheader
+AUTOMAKE = ${SHELL} /Users/Ben/Desktop/heimdall-1.1.0/libusb-1.0/missing --run automake-1.11
+AWK = gawk
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS =
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL =
+DSYMUTIL = dsymutil
+DUMPBIN =
+ECHO_C = \c
+ECHO_N =
+ECHO_T =
+EGREP = /usr/bin/grep -E
+EXEEXT =
+FGREP = /usr/bin/grep -F
+GREP = /usr/bin/grep
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LD = /usr/libexec/gcc/i686-apple-darwin10/4.2.1/ld
+LDFLAGS =
+LIBOBJS =
+LIBS =
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIBUSB_VERSION_MAJOR = 1
+LIBUSB_VERSION_MICRO = 8
+LIBUSB_VERSION_MINOR = 0
+LIBUSB_VERSION_NANO = 10323
+LIPO = lipo
+LN_S = ln -s
+LTLIBOBJS =
+MAINT =
+MAKEINFO = ${SHELL} /Users/Ben/Desktop/heimdall-1.1.0/libusb-1.0/missing --run makeinfo
+MKDIR_P = .././install-sh -c -d
+NM = /usr/bin/nm
+NMEDIT = nmedit
+OBJDUMP = false
+OBJEXT = o
+OS_DARWIN =
+OS_LINUX =
+OS_WINDOWS =
+OTOOL = otool
+OTOOL64 = :
+PACKAGE = libusb
+PACKAGE_BUGREPORT = libusb-devel@lists.sourceforge.net
+PACKAGE_NAME = libusb
+PACKAGE_STRING = libusb 1.0.8
+PACKAGE_TARNAME = libusb
+PACKAGE_URL = http://www.libusb.org/
+PACKAGE_VERSION = 1.0.8
+PATH_SEPARATOR = :
+PC_LIBS_PRIVATE = -Wl,-framework,IOKit -Wl,-framework,CoreFoundation -Wl,-prebind -no-undefined -pthread
+RANLIB = ranlib
+RC =
+SED = /opt/local/bin/gsed
+SET_MAKE =
+SHELL = /bin/sh
+STRIP = strip
+THREAD_CFLAGS = -pthread
+VERSION = 1.0.8
+VISIBILITY_CFLAGS = -fvisibility=hidden
+abs_builddir = /Users/Ben/Desktop/heimdall-1.1.0/libusb-1.0/libusb
+abs_srcdir = /Users/Ben/Desktop/heimdall-1.1.0/libusb-1.0/libusb
+abs_top_builddir = /Users/Ben/Desktop/heimdall-1.1.0/libusb-1.0
+abs_top_srcdir = /Users/Ben/Desktop/heimdall-1.1.0/libusb-1.0
+ac_ct_CC = gcc
+ac_ct_DUMPBIN =
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = ${AMTAR} chof - "$$tardir"
+am__untar = ${AMTAR} xf -
+bindir = ${exec_prefix}/bin
+build = i386-apple-darwin10.0.0
+build_alias =
+build_cpu = i386
+build_os = darwin10.0.0
+build_vendor = apple
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = i386-apple-darwin10.0.0
+host_alias =
+host_cpu = i386
+host_os = darwin10.0.0
+host_vendor = apple
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /Users/Ben/Desktop/heimdall-1.1.0/libusb-1.0/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+lt_ECHO = /bin/echo
+lt_age = 1
+lt_current = 1
+lt_revision = 0
+mandir = ${datarootdir}/man
+mkdir_p = $(top_builddir)/./install-sh -c -d
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target_alias =
+top_build_prefix = ../
+top_builddir = ..
+top_srcdir = ..
+lib_LTLIBRARIES = libusb-1.0.la
+LINUX_USBFS_SRC = os/linux_usbfs.c
+DARWIN_USB_SRC = os/darwin_usb.c
+WINDOWS_USB_SRC = os/poll_windows.c os/windows_usb.c libusb-1.0.rc
+EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(WINDOWS_USB_SRC) \
+ os/threads_windows.c
+
+OS_SRC = $(DARWIN_USB_SRC) $(am__append_1)
+#OS_SRC = $(LINUX_USBFS_SRC) $(am__append_1)
+#OS_SRC = $(WINDOWS_USB_SRC) $(am__append_1)
+AM_CFLAGS_EXT = -no-cpp-precomp
+libusb_1_0_la_CFLAGS = $(VISIBILITY_CFLAGS) $(AM_CFLAGS) $(THREAD_CFLAGS)
+libusb_1_0_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(lt_current):$(lt_revision):$(lt_age)
+libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c sync.c $(OS_SRC) \
+ os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h \
+ os/threads_posix.h os/threads_windows.h \
+ os/poll_posix.h os/poll_windows.h
+
+hdrdir = $(includedir)/libusb-1.0
+hdr_HEADERS = libusb.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj .rc
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libusb/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libusb/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+libusb_version.h: $(top_builddir)/config.status $(srcdir)/libusb_version.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libusb-1.0.la: $(libusb_1_0_la_OBJECTS) $(libusb_1_0_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libusb_1_0_la_LINK) -rpath $(libdir) $(libusb_1_0_la_OBJECTS) $(libusb_1_0_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+include ./$(DEPDIR)/libusb_1_0_la-core.Plo
+include ./$(DEPDIR)/libusb_1_0_la-darwin_usb.Plo
+include ./$(DEPDIR)/libusb_1_0_la-descriptor.Plo
+include ./$(DEPDIR)/libusb_1_0_la-io.Plo
+include ./$(DEPDIR)/libusb_1_0_la-linux_usbfs.Plo
+include ./$(DEPDIR)/libusb_1_0_la-poll_windows.Plo
+include ./$(DEPDIR)/libusb_1_0_la-sync.Plo
+include ./$(DEPDIR)/libusb_1_0_la-threads_windows.Plo
+include ./$(DEPDIR)/libusb_1_0_la-windows_usb.Plo
+
+.c.o:
+ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+# $(AM_V_CC) \
+# source='$<' object='$@' libtool=no \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(COMPILE) -c $<
+
+.c.obj:
+ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+# $(AM_V_CC) \
+# source='$<' object='$@' libtool=no \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+# $(AM_V_CC) \
+# source='$<' object='$@' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LTCOMPILE) -c -o $@ $<
+
+libusb_1_0_la-core.lo: core.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-core.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-core.Tpo -c -o libusb_1_0_la-core.lo `test -f 'core.c' || echo '$(srcdir)/'`core.c
+ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-core.Tpo $(DEPDIR)/libusb_1_0_la-core.Plo
+# $(AM_V_CC) \
+# source='core.c' object='libusb_1_0_la-core.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-core.lo `test -f 'core.c' || echo '$(srcdir)/'`core.c
+
+libusb_1_0_la-descriptor.lo: descriptor.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-descriptor.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-descriptor.Tpo -c -o libusb_1_0_la-descriptor.lo `test -f 'descriptor.c' || echo '$(srcdir)/'`descriptor.c
+ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-descriptor.Tpo $(DEPDIR)/libusb_1_0_la-descriptor.Plo
+# $(AM_V_CC) \
+# source='descriptor.c' object='libusb_1_0_la-descriptor.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-descriptor.lo `test -f 'descriptor.c' || echo '$(srcdir)/'`descriptor.c
+
+libusb_1_0_la-io.lo: io.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-io.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-io.Tpo -c -o libusb_1_0_la-io.lo `test -f 'io.c' || echo '$(srcdir)/'`io.c
+ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-io.Tpo $(DEPDIR)/libusb_1_0_la-io.Plo
+# $(AM_V_CC) \
+# source='io.c' object='libusb_1_0_la-io.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-io.lo `test -f 'io.c' || echo '$(srcdir)/'`io.c
+
+libusb_1_0_la-sync.lo: sync.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-sync.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-sync.Tpo -c -o libusb_1_0_la-sync.lo `test -f 'sync.c' || echo '$(srcdir)/'`sync.c
+ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-sync.Tpo $(DEPDIR)/libusb_1_0_la-sync.Plo
+# $(AM_V_CC) \
+# source='sync.c' object='libusb_1_0_la-sync.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-sync.lo `test -f 'sync.c' || echo '$(srcdir)/'`sync.c
+
+libusb_1_0_la-darwin_usb.lo: os/darwin_usb.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-darwin_usb.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-darwin_usb.Tpo -c -o libusb_1_0_la-darwin_usb.lo `test -f 'os/darwin_usb.c' || echo '$(srcdir)/'`os/darwin_usb.c
+ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-darwin_usb.Tpo $(DEPDIR)/libusb_1_0_la-darwin_usb.Plo
+# $(AM_V_CC) \
+# source='os/darwin_usb.c' object='libusb_1_0_la-darwin_usb.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-darwin_usb.lo `test -f 'os/darwin_usb.c' || echo '$(srcdir)/'`os/darwin_usb.c
+
+libusb_1_0_la-threads_windows.lo: os/threads_windows.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-threads_windows.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-threads_windows.Tpo -c -o libusb_1_0_la-threads_windows.lo `test -f 'os/threads_windows.c' || echo '$(srcdir)/'`os/threads_windows.c
+ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-threads_windows.Tpo $(DEPDIR)/libusb_1_0_la-threads_windows.Plo
+# $(AM_V_CC) \
+# source='os/threads_windows.c' object='libusb_1_0_la-threads_windows.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-threads_windows.lo `test -f 'os/threads_windows.c' || echo '$(srcdir)/'`os/threads_windows.c
+
+libusb_1_0_la-linux_usbfs.lo: os/linux_usbfs.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-linux_usbfs.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-linux_usbfs.Tpo -c -o libusb_1_0_la-linux_usbfs.lo `test -f 'os/linux_usbfs.c' || echo '$(srcdir)/'`os/linux_usbfs.c
+ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-linux_usbfs.Tpo $(DEPDIR)/libusb_1_0_la-linux_usbfs.Plo
+# $(AM_V_CC) \
+# source='os/linux_usbfs.c' object='libusb_1_0_la-linux_usbfs.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-linux_usbfs.lo `test -f 'os/linux_usbfs.c' || echo '$(srcdir)/'`os/linux_usbfs.c
+
+libusb_1_0_la-poll_windows.lo: os/poll_windows.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-poll_windows.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-poll_windows.Tpo -c -o libusb_1_0_la-poll_windows.lo `test -f 'os/poll_windows.c' || echo '$(srcdir)/'`os/poll_windows.c
+ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-poll_windows.Tpo $(DEPDIR)/libusb_1_0_la-poll_windows.Plo
+# $(AM_V_CC) \
+# source='os/poll_windows.c' object='libusb_1_0_la-poll_windows.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-poll_windows.lo `test -f 'os/poll_windows.c' || echo '$(srcdir)/'`os/poll_windows.c
+
+libusb_1_0_la-windows_usb.lo: os/windows_usb.c
+ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-windows_usb.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-windows_usb.Tpo -c -o libusb_1_0_la-windows_usb.lo `test -f 'os/windows_usb.c' || echo '$(srcdir)/'`os/windows_usb.c
+ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-windows_usb.Tpo $(DEPDIR)/libusb_1_0_la-windows_usb.Plo
+# $(AM_V_CC) \
+# source='os/windows_usb.c' object='libusb_1_0_la-windows_usb.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-windows_usb.lo `test -f 'os/windows_usb.c' || echo '$(srcdir)/'`os/windows_usb.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-hdrHEADERS: $(hdr_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(hdrdir)" || $(MKDIR_P) "$(DESTDIR)$(hdrdir)"
+ @list='$(hdr_HEADERS)'; test -n "$(hdrdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(hdrdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(hdrdir)" || exit $$?; \
+ done
+
+uninstall-hdrHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(hdr_HEADERS)'; test -n "$(hdrdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(hdrdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(hdrdir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(hdrdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-hdrHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-hdrHEADERS uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-hdrHEADERS \
+ install-html install-html-am install-info install-info-am \
+ install-libLTLIBRARIES install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-hdrHEADERS \
+ uninstall-libLTLIBRARIES
+
+all: libusb-1.0.la
+# Rebuild the import lib from the .def so that MS and MinGW DLLs can be interchanged
+# $(DLLTOOL) $(DLLTOOLFLAGS) --kill-at --input-def libusb-1.0.def --dllname libusb-1.0.dll --output-lib .libs/libusb-1.0.dll.a
+
+#.rc.lo:
+# $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(RC) $(RCFLAGS) -i $< -o $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libusb-1.0/libusb/Makefile.am b/libusb-1.0/libusb/Makefile.am
new file mode 100644
index 0000000..59eb5c4
--- /dev/null
+++ b/libusb-1.0/libusb/Makefile.am
@@ -0,0 +1,44 @@
+all: libusb-1.0.la
+if CREATE_IMPORT_LIB
+# Rebuild the import lib from the .def so that MS and MinGW DLLs can be interchanged
+ $(DLLTOOL) $(DLLTOOLFLAGS) --kill-at --input-def libusb-1.0.def --dllname libusb-1.0.dll --output-lib .libs/libusb-1.0.dll.a
+endif
+
+lib_LTLIBRARIES = libusb-1.0.la
+
+LINUX_USBFS_SRC = os/linux_usbfs.c
+DARWIN_USB_SRC = os/darwin_usb.c
+WINDOWS_USB_SRC = os/poll_windows.c os/windows_usb.c libusb-1.0.rc
+
+EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(WINDOWS_USB_SRC) \
+ os/threads_windows.c
+
+if OS_LINUX
+OS_SRC = $(LINUX_USBFS_SRC)
+endif
+
+if OS_DARWIN
+OS_SRC = $(DARWIN_USB_SRC)
+AM_CFLAGS_EXT = -no-cpp-precomp
+endif
+
+if OS_WINDOWS
+OS_SRC = $(WINDOWS_USB_SRC)
+
+if !THREADS_POSIX
+OS_SRC += os/threads_windows.c
+endif
+
+.rc.lo:
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(RC) $(RCFLAGS) -i $< -o $@
+endif
+
+libusb_1_0_la_CFLAGS = $(VISIBILITY_CFLAGS) $(AM_CFLAGS) $(THREAD_CFLAGS)
+libusb_1_0_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(lt_current):$(lt_revision):$(lt_age)
+libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c sync.c $(OS_SRC) \
+ os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h \
+ os/threads_posix.h os/threads_windows.h \
+ os/poll_posix.h os/poll_windows.h
+
+hdrdir = $(includedir)/libusb-1.0
+hdr_HEADERS = libusb.h
diff --git a/libusb-1.0/libusb/Makefile.in b/libusb-1.0/libusb/Makefile.in
new file mode 100644
index 0000000..944594c
--- /dev/null
+++ b/libusb-1.0/libusb/Makefile.in
@@ -0,0 +1,701 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@OS_WINDOWS_TRUE@@THREADS_POSIX_FALSE@am__append_1 = os/threads_windows.c
+subdir = libusb
+DIST_COMMON = $(hdr_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/libusb_version.h.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = libusb_version.h
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(hdrdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libusb_1_0_la_LIBADD =
+am__libusb_1_0_la_SOURCES_DIST = libusbi.h core.c descriptor.c io.c \
+ sync.c os/darwin_usb.c os/threads_windows.c os/linux_usbfs.c \
+ os/poll_windows.c os/windows_usb.c libusb-1.0.rc \
+ os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h \
+ os/threads_posix.h os/threads_windows.h os/poll_posix.h \
+ os/poll_windows.h
+am__objects_1 = libusb_1_0_la-darwin_usb.lo
+@OS_WINDOWS_TRUE@@THREADS_POSIX_FALSE@am__objects_2 = libusb_1_0_la-threads_windows.lo
+am__objects_3 = libusb_1_0_la-linux_usbfs.lo
+am__objects_4 = libusb_1_0_la-poll_windows.lo \
+ libusb_1_0_la-windows_usb.lo libusb-1.0.lo
+@OS_DARWIN_FALSE@@OS_LINUX_FALSE@@OS_WINDOWS_TRUE@am__objects_5 = $(am__objects_4) \
+@OS_DARWIN_FALSE@@OS_LINUX_FALSE@@OS_WINDOWS_TRUE@ $(am__objects_2)
+@OS_DARWIN_FALSE@@OS_LINUX_TRUE@am__objects_5 = $(am__objects_3) \
+@OS_DARWIN_FALSE@@OS_LINUX_TRUE@ $(am__objects_2)
+@OS_DARWIN_TRUE@am__objects_5 = $(am__objects_1) $(am__objects_2)
+am_libusb_1_0_la_OBJECTS = libusb_1_0_la-core.lo \
+ libusb_1_0_la-descriptor.lo libusb_1_0_la-io.lo \
+ libusb_1_0_la-sync.lo $(am__objects_5)
+libusb_1_0_la_OBJECTS = $(am_libusb_1_0_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+libusb_1_0_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libusb_1_0_la_CFLAGS) \
+ $(CFLAGS) $(libusb_1_0_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libusb_1_0_la_SOURCES)
+DIST_SOURCES = $(am__libusb_1_0_la_SOURCES_DIST)
+HEADERS = $(hdr_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUSB_VERSION_MAJOR = @LIBUSB_VERSION_MAJOR@
+LIBUSB_VERSION_MICRO = @LIBUSB_VERSION_MICRO@
+LIBUSB_VERSION_MINOR = @LIBUSB_VERSION_MINOR@
+LIBUSB_VERSION_NANO = @LIBUSB_VERSION_NANO@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OS_DARWIN = @OS_DARWIN@
+OS_LINUX = @OS_LINUX@
+OS_WINDOWS = @OS_WINDOWS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PC_LIBS_PRIVATE = @PC_LIBS_PRIVATE@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THREAD_CFLAGS = @THREAD_CFLAGS@
+VERSION = @VERSION@
+VISIBILITY_CFLAGS = @VISIBILITY_CFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+lt_age = @lt_age@
+lt_current = @lt_current@
+lt_revision = @lt_revision@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+lib_LTLIBRARIES = libusb-1.0.la
+LINUX_USBFS_SRC = os/linux_usbfs.c
+DARWIN_USB_SRC = os/darwin_usb.c
+WINDOWS_USB_SRC = os/poll_windows.c os/windows_usb.c libusb-1.0.rc
+EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(WINDOWS_USB_SRC) \
+ os/threads_windows.c
+
+@OS_DARWIN_TRUE@OS_SRC = $(DARWIN_USB_SRC) $(am__append_1)
+@OS_LINUX_TRUE@OS_SRC = $(LINUX_USBFS_SRC) $(am__append_1)
+@OS_WINDOWS_TRUE@OS_SRC = $(WINDOWS_USB_SRC) $(am__append_1)
+@OS_DARWIN_TRUE@AM_CFLAGS_EXT = -no-cpp-precomp
+libusb_1_0_la_CFLAGS = $(VISIBILITY_CFLAGS) $(AM_CFLAGS) $(THREAD_CFLAGS)
+libusb_1_0_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(lt_current):$(lt_revision):$(lt_age)
+libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c sync.c $(OS_SRC) \
+ os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h \
+ os/threads_posix.h os/threads_windows.h \
+ os/poll_posix.h os/poll_windows.h
+
+hdrdir = $(includedir)/libusb-1.0
+hdr_HEADERS = libusb.h
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj .rc
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libusb/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libusb/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+libusb_version.h: $(top_builddir)/config.status $(srcdir)/libusb_version.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libusb-1.0.la: $(libusb_1_0_la_OBJECTS) $(libusb_1_0_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libusb_1_0_la_LINK) -rpath $(libdir) $(libusb_1_0_la_OBJECTS) $(libusb_1_0_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-core.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-darwin_usb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-descriptor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-io.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-linux_usbfs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-poll_windows.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-sync.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-threads_windows.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-windows_usb.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+libusb_1_0_la-core.lo: core.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-core.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-core.Tpo -c -o libusb_1_0_la-core.lo `test -f 'core.c' || echo '$(srcdir)/'`core.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-core.Tpo $(DEPDIR)/libusb_1_0_la-core.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='core.c' object='libusb_1_0_la-core.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-core.lo `test -f 'core.c' || echo '$(srcdir)/'`core.c
+
+libusb_1_0_la-descriptor.lo: descriptor.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-descriptor.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-descriptor.Tpo -c -o libusb_1_0_la-descriptor.lo `test -f 'descriptor.c' || echo '$(srcdir)/'`descriptor.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-descriptor.Tpo $(DEPDIR)/libusb_1_0_la-descriptor.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='descriptor.c' object='libusb_1_0_la-descriptor.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-descriptor.lo `test -f 'descriptor.c' || echo '$(srcdir)/'`descriptor.c
+
+libusb_1_0_la-io.lo: io.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-io.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-io.Tpo -c -o libusb_1_0_la-io.lo `test -f 'io.c' || echo '$(srcdir)/'`io.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-io.Tpo $(DEPDIR)/libusb_1_0_la-io.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io.c' object='libusb_1_0_la-io.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-io.lo `test -f 'io.c' || echo '$(srcdir)/'`io.c
+
+libusb_1_0_la-sync.lo: sync.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-sync.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-sync.Tpo -c -o libusb_1_0_la-sync.lo `test -f 'sync.c' || echo '$(srcdir)/'`sync.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-sync.Tpo $(DEPDIR)/libusb_1_0_la-sync.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sync.c' object='libusb_1_0_la-sync.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-sync.lo `test -f 'sync.c' || echo '$(srcdir)/'`sync.c
+
+libusb_1_0_la-darwin_usb.lo: os/darwin_usb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-darwin_usb.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-darwin_usb.Tpo -c -o libusb_1_0_la-darwin_usb.lo `test -f 'os/darwin_usb.c' || echo '$(srcdir)/'`os/darwin_usb.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-darwin_usb.Tpo $(DEPDIR)/libusb_1_0_la-darwin_usb.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='os/darwin_usb.c' object='libusb_1_0_la-darwin_usb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-darwin_usb.lo `test -f 'os/darwin_usb.c' || echo '$(srcdir)/'`os/darwin_usb.c
+
+libusb_1_0_la-threads_windows.lo: os/threads_windows.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-threads_windows.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-threads_windows.Tpo -c -o libusb_1_0_la-threads_windows.lo `test -f 'os/threads_windows.c' || echo '$(srcdir)/'`os/threads_windows.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-threads_windows.Tpo $(DEPDIR)/libusb_1_0_la-threads_windows.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='os/threads_windows.c' object='libusb_1_0_la-threads_windows.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-threads_windows.lo `test -f 'os/threads_windows.c' || echo '$(srcdir)/'`os/threads_windows.c
+
+libusb_1_0_la-linux_usbfs.lo: os/linux_usbfs.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-linux_usbfs.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-linux_usbfs.Tpo -c -o libusb_1_0_la-linux_usbfs.lo `test -f 'os/linux_usbfs.c' || echo '$(srcdir)/'`os/linux_usbfs.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-linux_usbfs.Tpo $(DEPDIR)/libusb_1_0_la-linux_usbfs.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='os/linux_usbfs.c' object='libusb_1_0_la-linux_usbfs.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-linux_usbfs.lo `test -f 'os/linux_usbfs.c' || echo '$(srcdir)/'`os/linux_usbfs.c
+
+libusb_1_0_la-poll_windows.lo: os/poll_windows.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-poll_windows.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-poll_windows.Tpo -c -o libusb_1_0_la-poll_windows.lo `test -f 'os/poll_windows.c' || echo '$(srcdir)/'`os/poll_windows.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-poll_windows.Tpo $(DEPDIR)/libusb_1_0_la-poll_windows.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='os/poll_windows.c' object='libusb_1_0_la-poll_windows.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-poll_windows.lo `test -f 'os/poll_windows.c' || echo '$(srcdir)/'`os/poll_windows.c
+
+libusb_1_0_la-windows_usb.lo: os/windows_usb.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-windows_usb.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-windows_usb.Tpo -c -o libusb_1_0_la-windows_usb.lo `test -f 'os/windows_usb.c' || echo '$(srcdir)/'`os/windows_usb.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-windows_usb.Tpo $(DEPDIR)/libusb_1_0_la-windows_usb.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='os/windows_usb.c' object='libusb_1_0_la-windows_usb.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-windows_usb.lo `test -f 'os/windows_usb.c' || echo '$(srcdir)/'`os/windows_usb.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-hdrHEADERS: $(hdr_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(hdrdir)" || $(MKDIR_P) "$(DESTDIR)$(hdrdir)"
+ @list='$(hdr_HEADERS)'; test -n "$(hdrdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(hdrdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(hdrdir)" || exit $$?; \
+ done
+
+uninstall-hdrHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(hdr_HEADERS)'; test -n "$(hdrdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(hdrdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(hdrdir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(hdrdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-hdrHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-hdrHEADERS uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-hdrHEADERS \
+ install-html install-html-am install-info install-info-am \
+ install-libLTLIBRARIES install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-hdrHEADERS \
+ uninstall-libLTLIBRARIES
+
+all: libusb-1.0.la
+# Rebuild the import lib from the .def so that MS and MinGW DLLs can be interchanged
+@CREATE_IMPORT_LIB_TRUE@ $(DLLTOOL) $(DLLTOOLFLAGS) --kill-at --input-def libusb-1.0.def --dllname libusb-1.0.dll --output-lib .libs/libusb-1.0.dll.a
+
+@OS_WINDOWS_TRUE@.rc.lo:
+@OS_WINDOWS_TRUE@ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(RC) $(RCFLAGS) -i $< -o $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libusb-1.0/libusb/core.c b/libusb-1.0/libusb/core.c
new file mode 100644
index 0000000..46c2b9c
--- /dev/null
+++ b/libusb-1.0/libusb/core.c
@@ -0,0 +1,1738 @@
+/*
+ * Core functions for libusb
+ * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "libusbi.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_WINDOWS)
+const struct usbi_os_backend * const usbi_backend = &windows_backend;
+#else
+#error "Unsupported OS"
+#endif
+
+struct libusb_context *usbi_default_context = NULL;
+const struct libusb_version libusb_version_internal = { LIBUSB_VERSION_MAJOR,
+LIBUSB_VERSION_MINOR, LIBUSB_VERSION_MICRO, LIBUSB_VERSION_NANO};
+static int default_context_refcnt = 0;
+static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER;
+
+/**
+ * \mainpage libusb-1.0 API Reference
+ *
+ * \section intro Introduction
+ *
+ * libusb is an open source library that allows you to communicate with USB
+ * devices from userspace. For more info, see the
+ * <a href="http://libusb.sourceforge.net">libusb homepage</a>.
+ *
+ * This documentation is aimed at application developers wishing to
+ * communicate with USB peripherals from their own software. After reviewing
+ * this documentation, feedback and questions can be sent to the
+ * <a href="http://sourceforge.net/mail/?group_id=1674">libusb-devel mailing
+ * list</a>.
+ *
+ * This documentation assumes knowledge of how to operate USB devices from
+ * a software standpoint (descriptors, configurations, interfaces, endpoints,
+ * control/bulk/interrupt/isochronous transfers, etc). Full information
+ * can be found in the <a href="http://www.usb.org/developers/docs/">USB 2.0
+ * Specification</a> which is available for free download. You can probably
+ * find less verbose introductions by searching the web.
+ *
+ * \section features Library features
+ *
+ * - All transfer types supported (control/bulk/interrupt/isochronous)
+ * - 2 transfer interfaces:
+ * -# Synchronous (simple)
+ * -# Asynchronous (more complicated, but more powerful)
+ * - Thread safe (although the asynchronous interface means that you
+ * usually won't need to thread)
+ * - Lightweight with lean API
+ * - Compatible with libusb-0.1 through the libusb-compat-0.1 translation layer
+ *
+ * \section gettingstarted Getting Started
+ *
+ * To begin reading the API documentation, start with the Modules page which
+ * links to the different categories of libusb's functionality.
+ *
+ * One decision you will have to make is whether to use the synchronous
+ * or the asynchronous data transfer interface. The \ref io documentation
+ * provides some insight into this topic.
+ *
+ * Some example programs can be found in the libusb source distribution under
+ * the "examples" subdirectory. The libusb homepage includes a list of
+ * real-life project examples which use libusb.
+ *
+ * \section errorhandling Error handling
+ *
+ * libusb functions typically return 0 on success or a negative error code
+ * on failure. These negative error codes relate to LIBUSB_ERROR constants
+ * which are listed on the \ref misc "miscellaneous" documentation page.
+ *
+ * \section msglog Debug message logging
+ *
+ * libusb does not log any messages by default. Your application is therefore
+ * free to close stdout/stderr and those descriptors may be reused without
+ * worry.
+ *
+ * The libusb_set_debug() function can be used to enable stdout/stderr logging
+ * of certain messages. Under standard configuration, libusb doesn't really
+ * log much at all, so you are advised to use this function to enable all
+ * error/warning/informational messages. It will help you debug problems with
+ * your software.
+ *
+ * The logged messages are unstructured. There is no one-to-one correspondence
+ * between messages being logged and success or failure return codes from
+ * libusb functions. There is no format to the messages, so you should not
+ * try to capture or parse them. They are not and will not be localized.
+ * These messages are not suitable for being passed to your application user;
+ * instead, you should interpret the error codes returned from libusb functions
+ * and provide appropriate notification to the user. The messages are simply
+ * there to aid you as a programmer, and if you're confused because you're
+ * getting a strange error code from a libusb function, enabling message
+ * logging may give you a suitable explanation.
+ *
+ * The LIBUSB_DEBUG environment variable can be used to enable message logging
+ * at run-time. This environment variable should be set to a number, which is
+ * interpreted the same as the libusb_set_debug() parameter. When this
+ * environment variable is set, the message logging verbosity level is fixed
+ * and libusb_set_debug() effectively does nothing.
+ *
+ * libusb can be compiled without any logging functions, useful for embedded
+ * systems. In this case, libusb_set_debug() and the LIBUSB_DEBUG environment
+ * variable have no effects.
+ *
+ * libusb can also be compiled with verbose debugging messages. When the
+ * library is compiled in this way, all messages of all verbosities are always
+ * logged. libusb_set_debug() and the LIBUSB_DEBUG environment variable have
+ * no effects.
+ *
+ * \section remarks Other remarks
+ *
+ * libusb does have imperfections. The \ref caveats "caveats" page attempts
+ * to document these.
+ */
+
+/**
+ * \page caveats Caveats
+ *
+ * \section devresets Device resets
+ *
+ * The libusb_reset_device() function allows you to reset a device. If your
+ * program has to call such a function, it should obviously be aware that
+ * the reset will cause device state to change (e.g. register values may be
+ * reset).
+ *
+ * The problem is that any other program could reset the device your program
+ * is working with, at any time. libusb does not offer a mechanism to inform
+ * you when this has happened, so if someone else resets your device it will
+ * not be clear to your own program why the device state has changed.
+ *
+ * Ultimately, this is a limitation of writing drivers in userspace.
+ * Separation from the USB stack in the underlying kernel makes it difficult
+ * for the operating system to deliver such notifications to your program.
+ * The Linux kernel USB stack allows such reset notifications to be delivered
+ * to in-kernel USB drivers, but it is not clear how such notifications could
+ * be delivered to second-class drivers that live in userspace.
+ *
+ * \section blockonly Blocking-only functionality
+ *
+ * The functionality listed below is only available through synchronous,
+ * blocking functions. There are no asynchronous/non-blocking alternatives,
+ * and no clear ways of implementing these.
+ *
+ * - Configuration activation (libusb_set_configuration())
+ * - Interface/alternate setting activation (libusb_set_interface_alt_setting())
+ * - Releasing of interfaces (libusb_release_interface())
+ * - Clearing of halt/stall condition (libusb_clear_halt())
+ * - Device resets (libusb_reset_device())
+ *
+ * \section nohotplug No hotplugging
+ *
+ * libusb-1.0 lacks functionality for providing notifications of when devices
+ * are added or removed. This functionality is planned to be implemented
+ * for libusb-1.1.
+ *
+ * That said, there is basic disconnection handling for open device handles:
+ * - If there are ongoing transfers, libusb's handle_events loop will detect
+ * disconnections and complete ongoing transfers with the
+ * LIBUSB_TRANSFER_NO_DEVICE status code.
+ * - Many functions such as libusb_set_configuration() return the special
+ * LIBUSB_ERROR_NO_DEVICE error code when the device has been disconnected.
+ *
+ * \section configsel Configuration selection and handling
+ *
+ * When libusb presents a device handle to an application, there is a chance
+ * that the corresponding device may be in unconfigured state. For devices
+ * with multiple configurations, there is also a chance that the configuration
+ * currently selected is not the one that the application wants to use.
+ *
+ * The obvious solution is to add a call to libusb_set_configuration() early
+ * on during your device initialization routines, but there are caveats to
+ * be aware of:
+ * -# If the device is already in the desired configuration, calling
+ * libusb_set_configuration() using the same configuration value will cause
+ * a lightweight device reset. This may not be desirable behaviour.
+ * -# libusb will be unable to change configuration if the device is in
+ * another configuration and other programs or drivers have claimed
+ * interfaces under that configuration.
+ * -# In the case where the desired configuration is already active, libusb
+ * may not even be able to perform a lightweight device reset. For example,
+ * take my USB keyboard with fingerprint reader: I'm interested in driving
+ * the fingerprint reader interface through libusb, but the kernel's
+ * USB-HID driver will almost always have claimed the keyboard interface.
+ * Because the kernel has claimed an interface, it is not even possible to
+ * perform the lightweight device reset, so libusb_set_configuration() will
+ * fail. (Luckily the device in question only has a single configuration.)
+ *
+ * One solution to some of the above problems is to consider the currently
+ * active configuration. If the configuration we want is already active, then
+ * we don't have to select any configuration:
+\code
+cfg = libusb_get_configuration(dev);
+if (cfg != desired)
+ libusb_set_configuration(dev, desired);
+\endcode
+ *
+ * This is probably suitable for most scenarios, but is inherently racy:
+ * another application or driver may change the selected configuration
+ * <em>after</em> the libusb_get_configuration() call.
+ *
+ * Even in cases where libusb_set_configuration() succeeds, consider that other
+ * applications or drivers may change configuration after your application
+ * calls libusb_set_configuration().
+ *
+ * One possible way to lock your device into a specific configuration is as
+ * follows:
+ * -# Set the desired configuration (or use the logic above to realise that
+ * it is already in the desired configuration)
+ * -# Claim the interface that you wish to use
+ * -# Check that the currently active configuration is the one that you want
+ * to use.
+ *
+ * The above method works because once an interface is claimed, no application
+ * or driver is able to select another configuration.
+ *
+ * \section earlycomp Early transfer completion
+ *
+ * NOTE: This section is currently Linux-centric. I am not sure if any of these
+ * considerations apply to Darwin or other platforms.
+ *
+ * When a transfer completes early (i.e. when less data is received/sent in
+ * any one packet than the transfer buffer allows for) then libusb is designed
+ * to terminate the transfer immediately, not transferring or receiving any
+ * more data unless other transfers have been queued by the user.
+ *
+ * On legacy platforms, libusb is unable to do this in all situations. After
+ * the incomplete packet occurs, "surplus" data may be transferred. Prior to
+ * libusb v1.0.2, this information was lost (and for device-to-host transfers,
+ * the corresponding data was discarded). As of libusb v1.0.3, this information
+ * is kept (the data length of the transfer is updated) and, for device-to-host
+ * transfers, any surplus data was added to the buffer. Still, this is not
+ * a nice solution because it loses the information about the end of the short
+ * packet, and the user probably wanted that surplus data to arrive in the next
+ * logical transfer.
+ *
+ * A previous workaround was to only ever submit transfers of size 16kb or
+ * less.
+ *
+ * As of libusb v1.0.4 and Linux v2.6.32, this is fixed. A technical
+ * explanation of this issue follows.
+ *
+ * When you ask libusb to submit a bulk transfer larger than 16kb in size,
+ * libusb breaks it up into a number of smaller subtransfers. This is because
+ * the usbfs kernel interface only accepts transfers of up to 16kb in size.
+ * The subtransfers are submitted all at once so that the kernel can queue
+ * them at the hardware level, therefore maximizing bus throughput.
+ *
+ * On legacy platforms, this caused problems when transfers completed early.
+ * Upon this event, the kernel would terminate all further packets in that
+ * subtransfer (but not any following ones). libusb would note this event and
+ * immediately cancel any following subtransfers that had been queued,
+ * but often libusb was not fast enough, and the following subtransfers had
+ * started before libusb got around to cancelling them.
+ *
+ * Thanks to an API extension to usbfs, this is fixed with recent kernel and
+ * libusb releases. The solution was to allow libusb to communicate to the
+ * kernel where boundaries occur between logical libusb-level transfers. When
+ * a short transfer (or other error) occurs, the kernel will cancel all the
+ * subtransfers until the boundary without allowing those transfers to start.
+ */
+
+/**
+ * \page contexts Contexts
+ *
+ * It is possible that libusb may be used simultaneously from two independent
+ * libraries linked into the same executable. For example, if your application
+ * has a plugin-like system which allows the user to dynamically load a range
+ * of modules into your program, it is feasible that two independently
+ * developed modules may both use libusb.
+ *
+ * libusb is written to allow for these multiple user scenarios. The two
+ * "instances" of libusb will not interfere: libusb_set_debug() calls
+ * from one user will not affect the same settings for other users, other
+ * users can continue using libusb after one of them calls libusb_exit(), etc.
+ *
+ * This is made possible through libusb's <em>context</em> concept. When you
+ * call libusb_init(), you are (optionally) given a context. You can then pass
+ * this context pointer back into future libusb functions.
+ *
+ * In order to keep things simple for more simplistic applications, it is
+ * legal to pass NULL to all functions requiring a context pointer (as long as
+ * you're sure no other code will attempt to use libusb from the same process).
+ * When you pass NULL, the default context will be used. The default context
+ * is created the first time a process calls libusb_init() when no other
+ * context is alive. Contexts are destroyed during libusb_exit().
+ *
+ * The default context is reference-counted and can be shared. That means that
+ * if libusb_init(NULL) is called twice within the same process, the two
+ * users end up sharing the same context. The deinitialization and freeing of
+ * the default context will only happen when the last user calls libusb_exit().
+ * In other words, the default context is created and initialized when its
+ * reference count goes from 0 to 1, and is deinitialized and destroyed when
+ * its reference count goes from 1 to 0.
+ *
+ * You may be wondering why only a subset of libusb functions require a
+ * context pointer in their function definition. Internally, libusb stores
+ * context pointers in other objects (e.g. libusb_device instances) and hence
+ * can infer the context from those objects.
+ */
+
+/**
+ * @defgroup lib Library initialization/deinitialization
+ * This page details how to initialize and deinitialize libusb. Initialization
+ * must be performed before using any libusb functionality, and similarly you
+ * must not call any libusb functions after deinitialization.
+ */
+
+/**
+ * @defgroup dev Device handling and enumeration
+ * The functionality documented below is designed to help with the following
+ * operations:
+ * - Enumerating the USB devices currently attached to the system
+ * - Choosing a device to operate from your software
+ * - Opening and closing the chosen device
+ *
+ * \section nutshell In a nutshell...
+ *
+ * The description below really makes things sound more complicated than they
+ * actually are. The following sequence of function calls will be suitable
+ * for almost all scenarios and does not require you to have such a deep
+ * understanding of the resource management issues:
+ * \code
+// discover devices
+libusb_device **list;
+libusb_device *found = NULL;
+ssize_t cnt = libusb_get_device_list(NULL, &list);
+ssize_t i = 0;
+int err = 0;
+if (cnt < 0)
+ error();
+
+for (i = 0; i < cnt; i++) {
+ libusb_device *device = list[i];
+ if (is_interesting(device)) {
+ found = device;
+ break;
+ }
+}
+
+if (found) {
+ libusb_device_handle *handle;
+
+ err = libusb_open(found, &handle);
+ if (err)
+ error();
+ // etc
+}
+
+libusb_free_device_list(list, 1);
+\endcode
+ *
+ * The two important points:
+ * - You asked libusb_free_device_list() to unreference the devices (2nd
+ * parameter)
+ * - You opened the device before freeing the list and unreferencing the
+ * devices
+ *
+ * If you ended up with a handle, you can now proceed to perform I/O on the
+ * device.
+ *
+ * \section devshandles Devices and device handles
+ * libusb has a concept of a USB device, represented by the
+ * \ref libusb_device opaque type. A device represents a USB device that
+ * is currently or was previously connected to the system. Using a reference
+ * to a device, you can determine certain information about the device (e.g.
+ * you can read the descriptor data).
+ *
+ * The libusb_get_device_list() function can be used to obtain a list of
+ * devices currently connected to the system. This is known as device
+ * discovery.
+ *
+ * Just because you have a reference to a device does not mean it is
+ * necessarily usable. The device may have been unplugged, you may not have
+ * permission to operate such device, or another program or driver may be
+ * using the device.
+ *
+ * When you've found a device that you'd like to operate, you must ask
+ * libusb to open the device using the libusb_open() function. Assuming
+ * success, libusb then returns you a <em>device handle</em>
+ * (a \ref libusb_device_handle pointer). All "real" I/O operations then
+ * operate on the handle rather than the original device pointer.
+ *
+ * \section devref Device discovery and reference counting
+ *
+ * Device discovery (i.e. calling libusb_get_device_list()) returns a
+ * freshly-allocated list of devices. The list itself must be freed when
+ * you are done with it. libusb also needs to know when it is OK to free
+ * the contents of the list - the devices themselves.
+ *
+ * To handle these issues, libusb provides you with two separate items:
+ * - A function to free the list itself
+ * - A reference counting system for the devices inside
+ *
+ * New devices presented by the libusb_get_device_list() function all have a
+ * reference count of 1. You can increase and decrease reference count using
+ * libusb_ref_device() and libusb_unref_device(). A device is destroyed when
+ * its reference count reaches 0.
+ *
+ * With the above information in mind, the process of opening a device can
+ * be viewed as follows:
+ * -# Discover devices using libusb_get_device_list().
+ * -# Choose the device that you want to operate, and call libusb_open().
+ * -# Unref all devices in the discovered device list.
+ * -# Free the discovered device list.
+ *
+ * The order is important - you must not unreference the device before
+ * attempting to open it, because unreferencing it may destroy the device.
+ *
+ * For convenience, the libusb_free_device_list() function includes a
+ * parameter to optionally unreference all the devices in the list before
+ * freeing the list itself. This combines steps 3 and 4 above.
+ *
+ * As an implementation detail, libusb_open() actually adds a reference to
+ * the device in question. This is because the device remains available
+ * through the handle via libusb_get_device(). The reference is deleted during
+ * libusb_close().
+ */
+
+/** @defgroup misc Miscellaneous */
+
+/* we traverse usbfs without knowing how many devices we are going to find.
+ * so we create this discovered_devs model which is similar to a linked-list
+ * which grows when required. it can be freed once discovery has completed,
+ * eliminating the need for a list node in the libusb_device structure
+ * itself. */
+#define DISCOVERED_DEVICES_SIZE_STEP 8
+
+static struct discovered_devs *discovered_devs_alloc(void)
+{
+ struct discovered_devs *ret =
+ malloc(sizeof(*ret) + (sizeof(void *) * DISCOVERED_DEVICES_SIZE_STEP));
+
+ if (ret) {
+ ret->len = 0;
+ ret->capacity = DISCOVERED_DEVICES_SIZE_STEP;
+ }
+ return ret;
+}
+
+/* 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(
+ struct discovered_devs *discdevs, struct libusb_device *dev)
+{
+ size_t len = discdevs->len;
+ size_t capacity;
+
+ /* if there is space, just append the device */
+ if (len < discdevs->capacity) {
+ discdevs->devices[len] = libusb_ref_device(dev);
+ discdevs->len++;
+ return discdevs;
+ }
+
+ /* exceeded capacity, need to grow */
+ usbi_dbg("need to increase capacity");
+ capacity = discdevs->capacity + DISCOVERED_DEVICES_SIZE_STEP;
+ discdevs = realloc(discdevs,
+ sizeof(*discdevs) + (sizeof(void *) * capacity));
+ if (discdevs) {
+ discdevs->capacity = capacity;
+ discdevs->devices[len] = libusb_ref_device(dev);
+ discdevs->len++;
+ }
+
+ return discdevs;
+}
+
+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);
+}
+
+/* Allocate a new device with a specific session ID. The returned device has
+ * a reference count of 1. */
+struct libusb_device *usbi_alloc_device(struct libusb_context *ctx,
+ unsigned long session_id)
+{
+ size_t priv_size = usbi_backend->device_priv_size;
+ struct libusb_device *dev = malloc(sizeof(*dev) + priv_size);
+ int r;
+
+ if (!dev)
+ return NULL;
+
+ r = usbi_mutex_init(&dev->lock, NULL);
+ if (r) {
+ free(dev);
+ return NULL;
+ }
+
+ dev->ctx = ctx;
+ dev->refcnt = 1;
+ dev->session_data = session_id;
+ memset(&dev->os_priv, 0, priv_size);
+
+ usbi_mutex_lock(&ctx->usb_devs_lock);
+ list_add(&dev->list, &ctx->usb_devs);
+ usbi_mutex_unlock(&ctx->usb_devs_lock);
+ return dev;
+}
+
+/* Perform some final sanity checks on a newly discovered device. If this
+ * function fails (negative return code), the device should not be added
+ * to the discovered device list. */
+int usbi_sanitize_device(struct libusb_device *dev)
+{
+ int r;
+ unsigned char raw_desc[DEVICE_DESC_LENGTH];
+ uint8_t num_configurations;
+ int host_endian;
+
+ r = usbi_backend->get_device_descriptor(dev, raw_desc, &host_endian);
+ if (r < 0)
+ return r;
+
+ num_configurations = raw_desc[DEVICE_DESC_LENGTH - 1];
+ if (num_configurations > USB_MAXCONFIG) {
+ usbi_err(DEVICE_CTX(dev), "too many configurations");
+ return LIBUSB_ERROR_IO;
+ } else if (num_configurations < 1) {
+ usbi_dbg("no configurations?");
+ return LIBUSB_ERROR_IO;
+ }
+
+ dev->num_configurations = num_configurations;
+ return 0;
+}
+
+/* Examine libusb's internal list of known devices, looking for one with
+ * a specific session ID. Returns the matching device if it was found, and
+ * NULL otherwise. */
+struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx,
+ unsigned long session_id)
+{
+ struct libusb_device *dev;
+ struct libusb_device *ret = NULL;
+
+ usbi_mutex_lock(&ctx->usb_devs_lock);
+ list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device)
+ if (dev->session_data == session_id) {
+ ret = dev;
+ break;
+ }
+ usbi_mutex_unlock(&ctx->usb_devs_lock);
+
+ return ret;
+}
+
+/** @ingroup dev
+ * Returns a list of USB devices currently attached to the system. This is
+ * your entry point into finding a USB device to operate.
+ *
+ * You are expected to unreference all the devices when you are done with
+ * them, and then free the list with libusb_free_device_list(). Note that
+ * libusb_free_device_list() can unref all the devices for you. Be careful
+ * not to unreference a device you are about to open until after you have
+ * opened it.
+ *
+ * This return value of this function indicates the number of devices in
+ * the resultant list. The list is actually one element larger, as it is
+ * NULL-terminated.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param list output location for a list of devices. Must be later freed with
+ * libusb_free_device_list().
+ * \returns the number of devices in the outputted list, or LIBUSB_ERROR_NO_MEM
+ * on memory allocation failure.
+ */
+ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx,
+ libusb_device ***list)
+{
+ struct discovered_devs *discdevs = discovered_devs_alloc();
+ struct libusb_device **ret;
+ int r = 0;
+ ssize_t i, len;
+ USBI_GET_CONTEXT(ctx);
+ usbi_dbg("");
+
+ if (!discdevs)
+ return LIBUSB_ERROR_NO_MEM;
+
+ r = usbi_backend->get_device_list(ctx, &discdevs);
+ if (r < 0) {
+ len = r;
+ goto out;
+ }
+
+ /* convert discovered_devs into a list */
+ len = discdevs->len;
+ ret = malloc(sizeof(void *) * (len + 1));
+ if (!ret) {
+ len = LIBUSB_ERROR_NO_MEM;
+ goto out;
+ }
+
+ ret[len] = NULL;
+ for (i = 0; i < len; i++) {
+ struct libusb_device *dev = discdevs->devices[i];
+ ret[i] = libusb_ref_device(dev);
+ }
+ *list = ret;
+
+out:
+ discovered_devs_free(discdevs);
+ return len;
+}
+
+/** \ingroup dev
+ * Frees a list of devices previously discovered using
+ * libusb_get_device_list(). If the unref_devices parameter is set, the
+ * reference count of each device in the list is decremented by 1.
+ * \param list the list to free
+ * \param unref_devices whether to unref the devices in the list
+ */
+void API_EXPORTED libusb_free_device_list(libusb_device **list,
+ int unref_devices)
+{
+ if (!list)
+ return;
+
+ if (unref_devices) {
+ int i = 0;
+ struct libusb_device *dev;
+
+ while ((dev = list[i++]) != NULL)
+ libusb_unref_device(dev);
+ }
+ free(list);
+}
+
+/** \ingroup dev
+ * Get the number of the bus that a device is connected to.
+ * \param dev a device
+ * \returns the bus number
+ */
+uint8_t API_EXPORTED libusb_get_bus_number(libusb_device *dev)
+{
+ return dev->bus_number;
+}
+
+/** \ingroup dev
+ * Get the address of the device on the bus it is connected to.
+ * \param dev a device
+ * \returns the device address
+ */
+uint8_t API_EXPORTED libusb_get_device_address(libusb_device *dev)
+{
+ return dev->device_address;
+}
+
+static const struct libusb_endpoint_descriptor *find_endpoint(
+ struct libusb_config_descriptor *config, unsigned char endpoint)
+{
+ int iface_idx;
+ for (iface_idx = 0; iface_idx < config->bNumInterfaces; iface_idx++) {
+ const struct libusb_interface *iface = &config->interface[iface_idx];
+ int altsetting_idx;
+
+ for (altsetting_idx = 0; altsetting_idx < iface->num_altsetting;
+ altsetting_idx++) {
+ const struct libusb_interface_descriptor *altsetting
+ = &iface->altsetting[altsetting_idx];
+ int ep_idx;
+
+ for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints; ep_idx++) {
+ const struct libusb_endpoint_descriptor *ep =
+ &altsetting->endpoint[ep_idx];
+ if (ep->bEndpointAddress == endpoint)
+ return ep;
+ }
+ }
+ }
+ return NULL;
+}
+
+/** \ingroup dev
+ * Convenience function to retrieve the wMaxPacketSize value for a particular
+ * endpoint in the active device configuration.
+ *
+ * This function was originally intended to be of assistance when setting up
+ * isochronous transfers, but a design mistake resulted in this function
+ * instead. It simply returns the wMaxPacketSize value without considering
+ * its contents. If you're dealing with isochronous transfers, you probably
+ * want libusb_get_max_iso_packet_size() instead.
+ *
+ * \param dev a device
+ * \param endpoint address of the endpoint in question
+ * \returns the wMaxPacketSize value
+ * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist
+ * \returns LIBUSB_ERROR_OTHER on other failure
+ */
+int API_EXPORTED libusb_get_max_packet_size(libusb_device *dev,
+ unsigned char endpoint)
+{
+ struct libusb_config_descriptor *config;
+ const struct libusb_endpoint_descriptor *ep;
+ int r;
+
+ r = libusb_get_active_config_descriptor(dev, &config);
+ if (r < 0) {
+ usbi_err(DEVICE_CTX(dev),
+ "could not retrieve active config descriptor");
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ ep = find_endpoint(config, endpoint);
+ if (!ep)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ r = ep->wMaxPacketSize;
+ libusb_free_config_descriptor(config);
+ return r;
+}
+
+/** \ingroup dev
+ * Calculate the maximum packet size which a specific endpoint is capable is
+ * sending or receiving in the duration of 1 microframe
+ *
+ * Only the active configution is examined. The calculation is based on the
+ * wMaxPacketSize field in the endpoint descriptor as described in section
+ * 9.6.6 in the USB 2.0 specifications.
+ *
+ * If acting on an isochronous or interrupt endpoint, this function will
+ * multiply the value found in bits 0:10 by the number of transactions per
+ * microframe (determined by bits 11:12). Otherwise, this function just
+ * returns the numeric value found in bits 0:10.
+ *
+ * This function is useful for setting up isochronous transfers, for example
+ * you might pass the return value from this function to
+ * libusb_set_iso_packet_lengths() in order to set the length field of every
+ * isochronous packet in a transfer.
+ *
+ * Since v1.0.3.
+ *
+ * \param dev a device
+ * \param endpoint address of the endpoint in question
+ * \returns the maximum packet size which can be sent/received on this endpoint
+ * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist
+ * \returns LIBUSB_ERROR_OTHER on other failure
+ */
+int API_EXPORTED libusb_get_max_iso_packet_size(libusb_device *dev,
+ unsigned char endpoint)
+{
+ struct libusb_config_descriptor *config;
+ const struct libusb_endpoint_descriptor *ep;
+ enum libusb_transfer_type ep_type;
+ uint16_t val;
+ int r;
+
+ r = libusb_get_active_config_descriptor(dev, &config);
+ if (r < 0) {
+ usbi_err(DEVICE_CTX(dev),
+ "could not retrieve active config descriptor");
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ ep = find_endpoint(config, endpoint);
+ if (!ep)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ val = ep->wMaxPacketSize;
+ ep_type = ep->bmAttributes & 0x3;
+ libusb_free_config_descriptor(config);
+
+ r = val & 0x07ff;
+ if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
+ || ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT)
+ r *= (1 + ((val >> 11) & 3));
+ return r;
+}
+
+/** \ingroup dev
+ * Increment the reference count of a device.
+ * \param dev the device to reference
+ * \returns the same device
+ */
+DEFAULT_VISIBILITY
+libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev)
+{
+ usbi_mutex_lock(&dev->lock);
+ dev->refcnt++;
+ usbi_mutex_unlock(&dev->lock);
+ return dev;
+}
+
+/** \ingroup dev
+ * Decrement the reference count of a device. If the decrement operation
+ * causes the reference count to reach zero, the device shall be destroyed.
+ * \param dev the device to unreference
+ */
+void API_EXPORTED libusb_unref_device(libusb_device *dev)
+{
+ int refcnt;
+
+ if (!dev)
+ return;
+
+ usbi_mutex_lock(&dev->lock);
+ refcnt = --dev->refcnt;
+ usbi_mutex_unlock(&dev->lock);
+
+ if (refcnt == 0) {
+ usbi_dbg("destroy device %d.%d", dev->bus_number, dev->device_address);
+
+ if (usbi_backend->destroy_device)
+ usbi_backend->destroy_device(dev);
+
+ usbi_mutex_lock(&dev->ctx->usb_devs_lock);
+ list_del(&dev->list);
+ usbi_mutex_unlock(&dev->ctx->usb_devs_lock);
+
+ usbi_mutex_destroy(&dev->lock);
+ free(dev);
+ }
+}
+
+/*
+ * Interrupt the iteration of the event handling thread, so that it picks
+ * up the new fd.
+ */
+void usbi_fd_notification(struct libusb_context *ctx)
+{
+ unsigned char dummy = 1;
+ ssize_t r;
+
+ if (ctx == NULL)
+ return;
+
+ /* record that we are messing with poll fds */
+ usbi_mutex_lock(&ctx->pollfd_modify_lock);
+ ctx->pollfd_modify++;
+ usbi_mutex_unlock(&ctx->pollfd_modify_lock);
+
+ /* write some data on control pipe to interrupt event handlers */
+ r = usbi_write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
+ if (r <= 0) {
+ usbi_warn(ctx, "internal signalling write failed");
+ usbi_mutex_lock(&ctx->pollfd_modify_lock);
+ ctx->pollfd_modify--;
+ usbi_mutex_unlock(&ctx->pollfd_modify_lock);
+ return;
+ }
+
+ /* take event handling lock */
+ libusb_lock_events(ctx);
+
+ /* read the dummy data */
+ r = usbi_read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy));
+ if (r <= 0)
+ usbi_warn(ctx, "internal signalling read failed");
+
+ /* we're done with modifying poll fds */
+ usbi_mutex_lock(&ctx->pollfd_modify_lock);
+ ctx->pollfd_modify--;
+ usbi_mutex_unlock(&ctx->pollfd_modify_lock);
+
+ /* Release event handling lock and wake up event waiters */
+ libusb_unlock_events(ctx);
+}
+
+/** \ingroup dev
+ * Open a device and obtain a device handle. A handle allows you to perform
+ * I/O on the device in question.
+ *
+ * Internally, this function adds a reference to the device and makes it
+ * available to you through libusb_get_device(). This reference is removed
+ * during libusb_close().
+ *
+ * This is a non-blocking function; no requests are sent over the bus.
+ *
+ * \param dev the device to open
+ * \param handle output location for the returned device handle pointer. Only
+ * populated when the return code is 0.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NO_MEM on memory allocation failure
+ * \returns LIBUSB_ERROR_ACCESS if the user has insufficient permissions
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_open(libusb_device *dev,
+ libusb_device_handle **handle)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev);
+ struct libusb_device_handle *_handle;
+ size_t priv_size = usbi_backend->device_handle_priv_size;
+ int r;
+ usbi_dbg("open %d.%d", dev->bus_number, dev->device_address);
+
+ _handle = malloc(sizeof(*_handle) + priv_size);
+ if (!_handle)
+ return LIBUSB_ERROR_NO_MEM;
+
+ r = usbi_mutex_init(&_handle->lock, NULL);
+ if (r) {
+ free(_handle);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ _handle->dev = libusb_ref_device(dev);
+ _handle->claimed_interfaces = 0;
+ memset(&_handle->os_priv, 0, priv_size);
+
+ r = usbi_backend->open(_handle);
+ if (r < 0) {
+ libusb_unref_device(dev);
+ usbi_mutex_destroy(&_handle->lock);
+ free(_handle);
+ return r;
+ }
+
+ usbi_mutex_lock(&ctx->open_devs_lock);
+ list_add(&_handle->list, &ctx->open_devs);
+ usbi_mutex_unlock(&ctx->open_devs_lock);
+ *handle = _handle;
+
+ /* At this point, we want to interrupt any existing event handlers so
+ * that they realise the addition of the new device's poll fd. One
+ * example when this is desirable is if the user is running a separate
+ * dedicated libusb events handling thread, which is running with a long
+ * or infinite timeout. We want to interrupt that iteration of the loop,
+ * so that it picks up the new fd, and then continues. */
+ usbi_fd_notification(ctx);
+
+ return 0;
+}
+
+/** \ingroup dev
+ * Convenience function for finding a device with a particular
+ * <tt>idVendor</tt>/<tt>idProduct</tt> combination. This function is intended
+ * for those scenarios where you are using libusb to knock up a quick test
+ * application - it allows you to avoid calling libusb_get_device_list() and
+ * worrying about traversing/freeing the list.
+ *
+ * This function has limitations and is hence not intended for use in real
+ * applications: if multiple devices have the same IDs it will only
+ * give you the first one, etc.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param vendor_id the idVendor value to search for
+ * \param product_id the idProduct value to search for
+ * \returns a handle for the first found device, or NULL on error or if the
+ * device could not be found. */
+DEFAULT_VISIBILITY
+libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid(
+ libusb_context *ctx, uint16_t vendor_id, uint16_t product_id)
+{
+ struct libusb_device **devs;
+ struct libusb_device *found = NULL;
+ struct libusb_device *dev;
+ struct libusb_device_handle *handle = NULL;
+ size_t i = 0;
+ int r;
+
+ if (libusb_get_device_list(ctx, &devs) < 0)
+ return NULL;
+
+ while ((dev = devs[i++]) != NULL) {
+ struct libusb_device_descriptor desc;
+ r = libusb_get_device_descriptor(dev, &desc);
+ if (r < 0)
+ goto out;
+ if (desc.idVendor == vendor_id && desc.idProduct == product_id) {
+ found = dev;
+ break;
+ }
+ }
+
+ if (found) {
+ r = libusb_open(found, &handle);
+ if (r < 0)
+ handle = NULL;
+ }
+
+out:
+ libusb_free_device_list(devs, 1);
+ return handle;
+}
+
+static void do_close(struct libusb_context *ctx,
+ struct libusb_device_handle *dev_handle)
+{
+ usbi_mutex_lock(&ctx->open_devs_lock);
+ list_del(&dev_handle->list);
+ usbi_mutex_unlock(&ctx->open_devs_lock);
+
+ usbi_backend->close(dev_handle);
+ libusb_unref_device(dev_handle->dev);
+ usbi_mutex_destroy(&dev_handle->lock);
+ free(dev_handle);
+}
+
+/** \ingroup dev
+ * Close a device handle. Should be called on all open handles before your
+ * application exits.
+ *
+ * Internally, this function destroys the reference that was added by
+ * libusb_open() on the given device.
+ *
+ * This is a non-blocking function; no requests are sent over the bus.
+ *
+ * \param dev_handle the handle to close
+ */
+void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
+{
+ struct libusb_context *ctx;
+ unsigned char dummy = 1;
+ ssize_t r;
+
+ if (!dev_handle)
+ return;
+ usbi_dbg("");
+
+ ctx = HANDLE_CTX(dev_handle);
+
+ /* 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 messing with poll fds */
+ usbi_mutex_lock(&ctx->pollfd_modify_lock);
+ ctx->pollfd_modify++;
+ usbi_mutex_unlock(&ctx->pollfd_modify_lock);
+
+ /* write some data on control pipe to interrupt event handlers */
+ r = usbi_write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
+ if (r <= 0) {
+ usbi_warn(ctx, "internal signalling write failed, closing anyway");
+ do_close(ctx, dev_handle);
+ usbi_mutex_lock(&ctx->pollfd_modify_lock);
+ ctx->pollfd_modify--;
+ usbi_mutex_unlock(&ctx->pollfd_modify_lock);
+ return;
+ }
+
+ /* take event handling lock */
+ libusb_lock_events(ctx);
+
+ /* read the dummy data */
+ r = usbi_read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy));
+ if (r <= 0)
+ usbi_warn(ctx, "internal signalling read failed, closing anyway");
+
+ /* Close the device */
+ do_close(ctx, dev_handle);
+
+ /* we're done with modifying poll fds */
+ usbi_mutex_lock(&ctx->pollfd_modify_lock);
+ ctx->pollfd_modify--;
+ usbi_mutex_unlock(&ctx->pollfd_modify_lock);
+
+ /* Release event handling lock and wake up event waiters */
+ libusb_unlock_events(ctx);
+}
+
+/** \ingroup dev
+ * Get the underlying device for a handle. This function does not modify
+ * the reference count of the returned device, so do not feel compelled to
+ * unreference it when you are done.
+ * \param dev_handle a device handle
+ * \returns the underlying device
+ */
+DEFAULT_VISIBILITY
+libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle)
+{
+ return dev_handle->dev;
+}
+
+/** \ingroup dev
+ * Determine the bConfigurationValue of the currently active configuration.
+ *
+ * You could formulate your own control request to obtain this information,
+ * but this function has the advantage that it may be able to retrieve the
+ * information from operating system caches (no I/O involved).
+ *
+ * If the OS does not cache this information, then this function will block
+ * while a control transfer is submitted to retrieve the information.
+ *
+ * This function will return a value of 0 in the <tt>config</tt> output
+ * parameter if the device is in unconfigured state.
+ *
+ * \param dev a device handle
+ * \param config output location for the bConfigurationValue of the active
+ * configuration (only valid for return code 0)
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev,
+ int *config)
+{
+ int r = LIBUSB_ERROR_NOT_SUPPORTED;
+
+ usbi_dbg("");
+ if (usbi_backend->get_configuration)
+ r = usbi_backend->get_configuration(dev, config);
+
+ if (r == LIBUSB_ERROR_NOT_SUPPORTED) {
+ uint8_t tmp = 0;
+ usbi_dbg("falling back to control message");
+ r = libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN,
+ LIBUSB_REQUEST_GET_CONFIGURATION, 0, 0, &tmp, 1, 1000);
+ if (r == 0) {
+ usbi_err(HANDLE_CTX(dev), "zero bytes returned in ctrl transfer?");
+ r = LIBUSB_ERROR_IO;
+ } else if (r == 1) {
+ r = 0;
+ *config = tmp;
+ } else {
+ usbi_dbg("control failed, error %d", r);
+ }
+ }
+
+ if (r == 0)
+ usbi_dbg("active config %d", *config);
+
+ return r;
+}
+
+/** \ingroup dev
+ * Set the active configuration for a device.
+ *
+ * The operating system may or may not have already set an active
+ * configuration on the device. It is up to your application to ensure the
+ * correct configuration is selected before you attempt to claim interfaces
+ * and perform other operations.
+ *
+ * If you call this function on a device already configured with the selected
+ * configuration, then this function will act as a lightweight device reset:
+ * it will issue a SET_CONFIGURATION request using the current configuration,
+ * causing most USB-related device state to be reset (altsetting reset to zero,
+ * endpoint halts cleared, toggles reset).
+ *
+ * You cannot change/reset configuration if your application has claimed
+ * interfaces - you should free them with libusb_release_interface() first.
+ * You cannot change/reset configuration if other applications or drivers have
+ * claimed interfaces.
+ *
+ * A configuration value of -1 will put the device in unconfigured state.
+ * The USB specifications state that a configuration value of 0 does this,
+ * however buggy devices exist which actually have a configuration 0.
+ *
+ * You should always use this function rather than formulating your own
+ * SET_CONFIGURATION control request. This is because the underlying operating
+ * system needs to know when such changes happen.
+ *
+ * This is a blocking function.
+ *
+ * \param dev a device handle
+ * \param configuration the bConfigurationValue of the configuration you
+ * wish to activate, or -1 if you wish to put the device in unconfigured state
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the requested configuration does not exist
+ * \returns LIBUSB_ERROR_BUSY if interfaces are currently claimed
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev,
+ int configuration)
+{
+ usbi_dbg("configuration %d", configuration);
+ return usbi_backend->set_configuration(dev, configuration);
+}
+
+/** \ingroup dev
+ * Claim an interface on a given device handle. You must claim the interface
+ * you wish to use before you can perform I/O on any of its endpoints.
+ *
+ * It is legal to attempt to claim an already-claimed interface, in which
+ * case libusb just returns 0 without doing anything.
+ *
+ * Claiming of interfaces is a purely logical operation; it does not cause
+ * any requests to be sent over the bus. Interface claiming is used to
+ * instruct the underlying operating system that your application wishes
+ * to take ownership of the interface.
+ *
+ * This is a non-blocking function.
+ *
+ * \param dev a device handle
+ * \param interface_number the <tt>bInterfaceNumber</tt> of the interface you
+ * wish to claim
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the requested interface does not exist
+ * \returns LIBUSB_ERROR_BUSY if another program or driver has claimed the
+ * interface
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns a LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev,
+ int interface_number)
+{
+ int r = 0;
+
+ usbi_dbg("interface %d", interface_number);
+ if (interface_number >= sizeof(dev->claimed_interfaces) * 8)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ usbi_mutex_lock(&dev->lock);
+ if (dev->claimed_interfaces & (1 << interface_number))
+ goto out;
+
+ r = usbi_backend->claim_interface(dev, interface_number);
+ if (r == 0)
+ dev->claimed_interfaces |= 1 << interface_number;
+
+out:
+ usbi_mutex_unlock(&dev->lock);
+ return r;
+}
+
+/** \ingroup dev
+ * Release an interface previously claimed with libusb_claim_interface(). You
+ * should release all claimed interfaces before closing a device handle.
+ *
+ * This is a blocking function. A SET_INTERFACE control request will be sent
+ * to the device, resetting interface state to the first alternate setting.
+ *
+ * \param dev a device handle
+ * \param interface_number the <tt>bInterfaceNumber</tt> of the
+ * previously-claimed interface
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the interface was not claimed
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_release_interface(libusb_device_handle *dev,
+ int interface_number)
+{
+ int r;
+
+ usbi_dbg("interface %d", interface_number);
+ if (interface_number >= sizeof(dev->claimed_interfaces) * 8)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ usbi_mutex_lock(&dev->lock);
+ if (!(dev->claimed_interfaces & (1 << interface_number))) {
+ r = LIBUSB_ERROR_NOT_FOUND;
+ goto out;
+ }
+
+ r = usbi_backend->release_interface(dev, interface_number);
+ if (r == 0)
+ dev->claimed_interfaces &= ~(1 << interface_number);
+
+out:
+ usbi_mutex_unlock(&dev->lock);
+ return r;
+}
+
+/** \ingroup dev
+ * Activate an alternate setting for an interface. The interface must have
+ * been previously claimed with libusb_claim_interface().
+ *
+ * You should always use this function rather than formulating your own
+ * SET_INTERFACE control request. This is because the underlying operating
+ * system needs to know when such changes happen.
+ *
+ * This is a blocking function.
+ *
+ * \param dev a device handle
+ * \param interface_number the <tt>bInterfaceNumber</tt> of the
+ * previously-claimed interface
+ * \param alternate_setting the <tt>bAlternateSetting</tt> of the alternate
+ * setting to activate
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the interface was not claimed, or the
+ * requested alternate setting does not exist
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev,
+ int interface_number, int alternate_setting)
+{
+ usbi_dbg("interface %d altsetting %d",
+ interface_number, alternate_setting);
+ if (interface_number >= sizeof(dev->claimed_interfaces) * 8)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ usbi_mutex_lock(&dev->lock);
+ if (!(dev->claimed_interfaces & (1 << interface_number))) {
+ usbi_mutex_unlock(&dev->lock);
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+ usbi_mutex_unlock(&dev->lock);
+
+ return usbi_backend->set_interface_altsetting(dev, interface_number,
+ alternate_setting);
+}
+
+/** \ingroup dev
+ * Clear the halt/stall condition for an endpoint. Endpoints with halt status
+ * are unable to receive or transmit data until the halt condition is stalled.
+ *
+ * You should cancel all pending transfers before attempting to clear the halt
+ * condition.
+ *
+ * This is a blocking function.
+ *
+ * \param dev a device handle
+ * \param endpoint the endpoint to clear halt status
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_clear_halt(libusb_device_handle *dev,
+ unsigned char endpoint)
+{
+ usbi_dbg("endpoint %x", endpoint);
+ return usbi_backend->clear_halt(dev, endpoint);
+}
+
+/** \ingroup dev
+ * Perform a USB port reset to reinitialize a device. The system will attempt
+ * to restore the previous configuration and alternate settings after the
+ * reset has completed.
+ *
+ * If the reset fails, the descriptors change, or the previous state cannot be
+ * restored, the device will appear to be disconnected and reconnected. This
+ * means that the device handle is no longer valid (you should close it) and
+ * rediscover the device. A return code of LIBUSB_ERROR_NOT_FOUND indicates
+ * when this is the case.
+ *
+ * This is a blocking function which usually incurs a noticeable delay.
+ *
+ * \param dev a handle of the device to reset
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the
+ * device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_reset_device(libusb_device_handle *dev)
+{
+ usbi_dbg("");
+ return usbi_backend->reset_device(dev);
+}
+
+/** \ingroup dev
+ * Determine if a kernel driver is active on an interface. If a kernel driver
+ * is active, you cannot claim the interface, and libusb will be unable to
+ * perform I/O.
+ *
+ * This functionality is not available on Windows.
+ *
+ * \param dev a device handle
+ * \param interface_number the interface to check
+ * \returns 0 if no kernel driver is active
+ * \returns 1 if a kernel driver is active
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality
+ * is not available
+ * \returns another LIBUSB_ERROR code on other failure
+ * \see libusb_detach_kernel_driver()
+ */
+int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev,
+ int interface_number)
+{
+ usbi_dbg("interface %d", interface_number);
+ if (usbi_backend->kernel_driver_active)
+ return usbi_backend->kernel_driver_active(dev, interface_number);
+ else
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+/** \ingroup dev
+ * Detach a kernel driver from an interface. If successful, you will then be
+ * able to claim the interface and perform I/O.
+ *
+ * This functionality is not available on Darwin or Windows.
+ *
+ * \param dev a device handle
+ * \param interface_number the interface to detach the driver from
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active
+ * \returns LIBUSB_ERROR_INVALID_PARAM if the interface does not exist
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality
+ * is not available
+ * \returns another LIBUSB_ERROR code on other failure
+ * \see libusb_kernel_driver_active()
+ */
+int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev,
+ int interface_number)
+{
+ usbi_dbg("interface %d", interface_number);
+ if (usbi_backend->detach_kernel_driver)
+ return usbi_backend->detach_kernel_driver(dev, interface_number);
+ else
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+/** \ingroup dev
+ * Re-attach an interface's kernel driver, which was previously detached
+ * using libusb_detach_kernel_driver(). This call is only effective on
+ * Linux and returns LIBUSB_ERROR_NOT_SUPPORTED on all other platforms.
+ *
+ * This functionality is not available on Darwin or Windows.
+ *
+ * \param dev a device handle
+ * \param interface_number the interface to attach the driver from
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active
+ * \returns LIBUSB_ERROR_INVALID_PARAM if the interface does not exist
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality
+ * is not available
+ * \returns LIBUSB_ERROR_BUSY if the driver cannot be attached because the
+ * interface is claimed by a program or driver
+ * \returns another LIBUSB_ERROR code on other failure
+ * \see libusb_kernel_driver_active()
+ */
+int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev,
+ int interface_number)
+{
+ usbi_dbg("interface %d", interface_number);
+ if (usbi_backend->attach_kernel_driver)
+ return usbi_backend->attach_kernel_driver(dev, interface_number);
+ else
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+/** \ingroup lib
+ * Set message verbosity.
+ * - Level 0: no messages ever printed by the library (default)
+ * - Level 1: error messages are printed to stderr
+ * - Level 2: warning and error messages are printed to stderr
+ * - Level 3: informational messages are printed to stdout, warning and error
+ * messages are printed to stderr
+ *
+ * The default level is 0, which means no messages are ever printed. If you
+ * choose to increase the message verbosity level, ensure that your
+ * application does not close the stdout/stderr file descriptors.
+ *
+ * You are advised to set level 3. 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.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param level debug level to set
+ */
+void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level)
+{
+ USBI_GET_CONTEXT(ctx);
+ if (!ctx->debug_fixed)
+ ctx->debug = level;
+}
+
+/** \ingroup lib
+ * Initialize libusb. This function must be called before calling any other
+ * libusb function.
+ *
+ * If you do not provide an output location for a context pointer, a default
+ * context will be created. If there was already a default context, it will
+ * be reused (and nothing will be initialized/reinitialized).
+ *
+ * \param context Optional output location for context pointer.
+ * Only valid on return code 0.
+ * \returns 0 on success, or a LIBUSB_ERROR code on failure
+ * \see contexts
+ */
+int API_EXPORTED libusb_init(libusb_context **context)
+{
+ char *dbg = getenv("LIBUSB_DEBUG");
+ struct libusb_context *ctx;
+ int r;
+
+ usbi_mutex_static_lock(&default_context_lock);
+ if (!context && usbi_default_context) {
+ r = 0;
+ usbi_dbg("reusing default context");
+ default_context_refcnt++;
+ usbi_mutex_static_unlock(&default_context_lock);
+ return 0;
+ }
+
+ ctx = malloc(sizeof(*ctx));
+ if (!ctx) {
+ r = LIBUSB_ERROR_NO_MEM;
+ goto err_unlock;
+ }
+ memset(ctx, 0, sizeof(*ctx));
+
+ if (dbg) {
+ ctx->debug = atoi(dbg);
+ if (ctx->debug)
+ ctx->debug_fixed = 1;
+ }
+
+ // default context should be initialized before any call to usbi_dbg
+ if (!usbi_default_context) {
+ usbi_default_context = ctx;
+ usbi_dbg("created default context");
+ }
+
+ usbi_dbg("");
+
+ if (usbi_backend->init) {
+ r = usbi_backend->init(ctx);
+ if (r)
+ goto err_free_ctx;
+ }
+
+ usbi_mutex_init(&ctx->usb_devs_lock, NULL);
+ usbi_mutex_init(&ctx->open_devs_lock, NULL);
+ list_init(&ctx->usb_devs);
+ list_init(&ctx->open_devs);
+
+ r = usbi_io_init(ctx);
+ if (r < 0) {
+ if (usbi_backend->exit)
+ usbi_backend->exit();
+ goto err_destroy_mutex;
+ }
+
+ if (context) {
+ *context = ctx;
+ } else if (!usbi_default_context) {
+ usbi_dbg("created default context");
+ usbi_default_context = ctx;
+ default_context_refcnt++;
+ }
+ usbi_mutex_static_unlock(&default_context_lock);
+
+ return 0;
+
+err_destroy_mutex:
+ if (usbi_default_context == ctx)
+ usbi_default_context = NULL;
+ usbi_mutex_destroy(&ctx->open_devs_lock);
+ usbi_mutex_destroy(&ctx->usb_devs_lock);
+err_free_ctx:
+ free(ctx);
+err_unlock:
+ usbi_mutex_static_unlock(&default_context_lock);
+ return r;
+}
+
+/** \ingroup lib
+ * Deinitialize libusb. Should be called after closing all open devices and
+ * before your application terminates.
+ * \param ctx the context to deinitialize, or NULL for the default context
+ */
+void API_EXPORTED libusb_exit(struct libusb_context *ctx)
+{
+ USBI_GET_CONTEXT(ctx);
+ usbi_dbg("");
+
+ /* if working with default context, only actually do the deinitialization
+ * if we're the last user */
+ if (ctx == usbi_default_context) {
+ usbi_mutex_static_lock(&default_context_lock);
+ if (--default_context_refcnt > 0) {
+ usbi_dbg("not destroying default context");
+ usbi_mutex_static_unlock(&default_context_lock);
+ return;
+ }
+ usbi_dbg("destroying default context");
+ usbi_default_context = NULL;
+ usbi_mutex_static_unlock(&default_context_lock);
+ }
+
+ /* a little sanity check. doesn't bother with open_devs locking because
+ * unless there is an application bug, nobody will be accessing this. */
+ if (!list_empty(&ctx->open_devs))
+ usbi_warn(ctx, "application left some devices open");
+
+ usbi_io_exit(ctx);
+ if (usbi_backend->exit)
+ usbi_backend->exit();
+
+ usbi_mutex_destroy(&ctx->open_devs_lock);
+ usbi_mutex_destroy(&ctx->usb_devs_lock);
+ free(ctx);
+}
+
+void usbi_log_v(struct libusb_context *ctx, enum usbi_log_level level,
+ const char *function, const char *format, va_list args)
+{
+ FILE *stream = stdout;
+ const char *prefix;
+
+#ifndef ENABLE_DEBUG_LOGGING
+ USBI_GET_CONTEXT(ctx);
+ if (ctx == NULL)
+ return;
+ if (!ctx->debug)
+ return;
+ if (level == LOG_LEVEL_WARNING && ctx->debug < 2)
+ return;
+ if (level == LOG_LEVEL_INFO && ctx->debug < 3)
+ return;
+ if (level == LOG_LEVEL_DEBUG && ctx->debug < 4)
+ return;
+#endif
+
+ switch (level) {
+ case LOG_LEVEL_INFO:
+ prefix = "info";
+ break;
+ case LOG_LEVEL_WARNING:
+ stream = stderr;
+ prefix = "warning";
+ break;
+ case LOG_LEVEL_ERROR:
+ stream = stderr;
+ prefix = "error";
+ break;
+ case LOG_LEVEL_DEBUG:
+ stream = stderr;
+ prefix = "debug";
+ break;
+ default:
+ stream = stderr;
+ prefix = "unknown";
+ break;
+ }
+
+ fprintf(stream, "libusb:%s [%s] ", prefix, function);
+
+ vfprintf(stream, format, args);
+
+ fprintf(stream, "\n");
+}
+
+void usbi_log(struct libusb_context *ctx, enum usbi_log_level level,
+ const char *function, const char *format, ...)
+{
+ va_list args;
+
+ va_start (args, format);
+ usbi_log_v(ctx, level, function, format, args);
+ va_end (args);
+}
+
+/** \ingroup misc
+ * Returns a constant NULL-terminated string with an English short description
+ * of the given error code. The caller should never free() the returned pointer
+ * since it points to a constant string.
+ * The returned string is encoded in ASCII form and always starts with a
+ * capital letter and ends without any punctuation.
+ * Future versions of libusb may return NULL if the library is compiled without
+ * these messages included (e.g. for embedded systems).
+ * This function is intended to be used for debugging purposes only.
+ *
+ * \param errcode the error code whose description is desired
+ * \returns a short description of the error code in English, or NULL if the
+ * error descriptions are unavailable
+ */
+DEFAULT_VISIBILITY
+const char * LIBUSB_CALL libusb_strerror(enum libusb_error error_code)
+{
+ switch (error_code) {
+ case LIBUSB_SUCCESS:
+ return "Success";
+ case LIBUSB_ERROR_IO:
+ return "Input/output error";
+ case LIBUSB_ERROR_INVALID_PARAM:
+ return "Invalid parameter";
+ case LIBUSB_ERROR_ACCESS:
+ return "Access denied (insufficient permissions)";
+ case LIBUSB_ERROR_NO_DEVICE:
+ return "No such device (it may have been disconnected)";
+ case LIBUSB_ERROR_NOT_FOUND:
+ return "Entity not found";
+ case LIBUSB_ERROR_BUSY:
+ return "Resource busy";
+ case LIBUSB_ERROR_TIMEOUT:
+ return "Operation timed out";
+ case LIBUSB_ERROR_OVERFLOW:
+ return "Overflow";
+ case LIBUSB_ERROR_PIPE:
+ return "Pipe error";
+ case LIBUSB_ERROR_INTERRUPTED:
+ return "System call interrupted (perhaps due to signal)";
+ case LIBUSB_ERROR_NO_MEM:
+ return "Insufficient memory";
+ case LIBUSB_ERROR_NOT_SUPPORTED:
+ return "Operation not supported or unimplemented on this platform";
+ case LIBUSB_ERROR_OTHER:
+ return "Other error";
+ }
+ return "Unknown error";
+}
+
+/** \ingroup misc
+ * Fills a libusb_version struct with the full version (major, minor,
+ * micro, nano) of this library
+ */
+DEFAULT_VISIBILITY
+const struct libusb_version * LIBUSB_CALL libusb_getversion(void)
+{
+ return &libusb_version_internal;
+}
diff --git a/libusb-1.0/libusb/descriptor.c b/libusb-1.0/libusb/descriptor.c
new file mode 100644
index 0000000..54a47b4
--- /dev/null
+++ b/libusb-1.0/libusb/descriptor.c
@@ -0,0 +1,721 @@
+/*
+ * USB descriptor handling functions for libusb
+ * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libusbi.h"
+
+#define DESC_HEADER_LENGTH 2
+#define DEVICE_DESC_LENGTH 18
+#define CONFIG_DESC_LENGTH 9
+#define INTERFACE_DESC_LENGTH 9
+#define ENDPOINT_DESC_LENGTH 7
+#define ENDPOINT_AUDIO_DESC_LENGTH 9
+
+/** @defgroup desc USB descriptors
+ * This page details how to examine the various standard USB descriptors
+ * for detected devices
+ */
+
+/* set host_endian if the w values are already in host endian format,
+ * as opposed to bus endian. */
+int usbi_parse_descriptor(unsigned char *source, char *descriptor, void *dest,
+ int host_endian)
+{
+ unsigned char *sp = source, *dp = dest;
+ uint16_t w;
+ char *cp;
+
+ for (cp = descriptor; *cp; cp++) {
+ switch (*cp) {
+ case 'b': /* 8-bit byte */
+ *dp++ = *sp++;
+ break;
+ case 'w': /* 16-bit word, convert from little endian to CPU */
+ dp += ((uintptr_t)dp & 1); /* Align to word boundary */
+
+ if (host_endian) {
+ memcpy(dp, sp, 2);
+ } else {
+ w = (sp[1] << 8) | sp[0];
+ *((uint16_t *)dp) = w;
+ }
+ sp += 2;
+ dp += 2;
+ break;
+ }
+ }
+
+ return (int) (sp - source);
+}
+
+static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint)
+{
+ if (endpoint->extra)
+ free((unsigned char *) endpoint->extra);
+}
+
+static int parse_endpoint(struct libusb_context *ctx,
+ struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer,
+ int size, int host_endian)
+{
+ struct usb_descriptor_header header;
+ unsigned char *extra;
+ unsigned char *begin;
+ int parsed = 0;
+ int len;
+
+ usbi_parse_descriptor(buffer, "bb", &header, 0);
+
+ /* Everything should be fine being passed into here, but we sanity */
+ /* check JIC */
+ if (header.bLength > size) {
+ usbi_err(ctx, "ran out of descriptors parsing");
+ return -1;
+ }
+
+ if (header.bDescriptorType != LIBUSB_DT_ENDPOINT) {
+ usbi_err(ctx, "unexpected descriptor %x (expected %x)",
+ header.bDescriptorType, LIBUSB_DT_ENDPOINT);
+ return parsed;
+ }
+
+ if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH)
+ usbi_parse_descriptor(buffer, "bbbbwbbb", endpoint, host_endian);
+ else if (header.bLength >= ENDPOINT_DESC_LENGTH)
+ usbi_parse_descriptor(buffer, "bbbbwb", endpoint, host_endian);
+
+ buffer += header.bLength;
+ size -= header.bLength;
+ parsed += header.bLength;
+
+ /* Skip over the rest of the Class Specific or Vendor Specific */
+ /* descriptors */
+ begin = buffer;
+ while (size >= DESC_HEADER_LENGTH) {
+ usbi_parse_descriptor(buffer, "bb", &header, 0);
+
+ if (header.bLength < 2) {
+ usbi_err(ctx, "invalid descriptor length %d", header.bLength);
+ return -1;
+ }
+
+ /* If we find another "proper" descriptor then we're done */
+ if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
+ (header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
+ (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
+ (header.bDescriptorType == LIBUSB_DT_DEVICE))
+ break;
+
+ usbi_dbg("skipping descriptor %x", header.bDescriptorType);
+ buffer += header.bLength;
+ size -= header.bLength;
+ parsed += header.bLength;
+ }
+
+ /* Copy any unknown descriptors into a storage area for drivers */
+ /* to later parse */
+ len = (int)(buffer - begin);
+ if (!len) {
+ endpoint->extra = NULL;
+ endpoint->extra_length = 0;
+ return parsed;
+ }
+
+ extra = malloc(len);
+ endpoint->extra = extra;
+ if (!extra) {
+ endpoint->extra_length = 0;
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ memcpy(extra, begin, len);
+ endpoint->extra_length = len;
+
+ return parsed;
+}
+
+static void clear_interface(struct libusb_interface *usb_interface)
+{
+ int i;
+ int j;
+
+ if (usb_interface->altsetting) {
+ for (i = 0; i < usb_interface->num_altsetting; i++) {
+ struct libusb_interface_descriptor *ifp =
+ (struct libusb_interface_descriptor *)
+ usb_interface->altsetting + i;
+ if (ifp->extra)
+ free((void *) ifp->extra);
+ if (ifp->endpoint) {
+ for (j = 0; j < ifp->bNumEndpoints; j++)
+ clear_endpoint((struct libusb_endpoint_descriptor *)
+ ifp->endpoint + j);
+ free((void *) ifp->endpoint);
+ }
+ }
+ free((void *) usb_interface->altsetting);
+ usb_interface->altsetting = NULL;
+ }
+
+}
+
+static int parse_interface(libusb_context *ctx,
+ struct libusb_interface *usb_interface, unsigned char *buffer, int size,
+ int host_endian)
+{
+ int i;
+ int len;
+ int r;
+ int parsed = 0;
+ int tmp;
+ struct usb_descriptor_header header;
+ struct libusb_interface_descriptor *ifp;
+ unsigned char *begin;
+
+ usb_interface->num_altsetting = 0;
+
+ while (size >= INTERFACE_DESC_LENGTH) {
+ struct libusb_interface_descriptor *altsetting =
+ (struct libusb_interface_descriptor *) usb_interface->altsetting;
+ altsetting = realloc(altsetting,
+ sizeof(struct libusb_interface_descriptor) *
+ (usb_interface->num_altsetting + 1));
+ if (!altsetting) {
+ r = LIBUSB_ERROR_NO_MEM;
+ goto err;
+ }
+ usb_interface->altsetting = altsetting;
+
+ ifp = altsetting + usb_interface->num_altsetting;
+ usb_interface->num_altsetting++;
+ usbi_parse_descriptor(buffer, "bbbbbbbbb", ifp, 0);
+ ifp->extra = NULL;
+ ifp->extra_length = 0;
+ ifp->endpoint = NULL;
+
+ /* Skip over the interface */
+ buffer += ifp->bLength;
+ parsed += ifp->bLength;
+ size -= ifp->bLength;
+
+ begin = buffer;
+
+ /* Skip over any interface, class or vendor descriptors */
+ while (size >= DESC_HEADER_LENGTH) {
+ usbi_parse_descriptor(buffer, "bb", &header, 0);
+ if (header.bLength < 2) {
+ usbi_err(ctx, "invalid descriptor of length %d",
+ header.bLength);
+ r = LIBUSB_ERROR_IO;
+ goto err;
+ }
+
+ /* If we find another "proper" descriptor then we're done */
+ if ((header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
+ (header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
+ (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
+ (header.bDescriptorType == LIBUSB_DT_DEVICE))
+ break;
+
+ buffer += header.bLength;
+ parsed += header.bLength;
+ size -= header.bLength;
+ }
+
+ /* Copy any unknown descriptors into a storage area for */
+ /* drivers to later parse */
+ len = (int)(buffer - begin);
+ if (len) {
+ ifp->extra = malloc(len);
+ if (!ifp->extra) {
+ r = LIBUSB_ERROR_NO_MEM;
+ goto err;
+ }
+ memcpy((unsigned char *) ifp->extra, begin, len);
+ ifp->extra_length = len;
+ }
+
+ /* Did we hit an unexpected descriptor? */
+ usbi_parse_descriptor(buffer, "bb", &header, 0);
+ if ((size >= DESC_HEADER_LENGTH) &&
+ ((header.bDescriptorType == LIBUSB_DT_CONFIG) ||
+ (header.bDescriptorType == LIBUSB_DT_DEVICE)))
+ return parsed;
+
+ if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
+ usbi_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoints);
+ r = LIBUSB_ERROR_IO;
+ goto err;
+ }
+
+ if (ifp->bNumEndpoints > 0) {
+ struct libusb_endpoint_descriptor *endpoint;
+ tmp = ifp->bNumEndpoints * sizeof(struct libusb_endpoint_descriptor);
+ endpoint = malloc(tmp);
+ ifp->endpoint = endpoint;
+ if (!endpoint) {
+ r = LIBUSB_ERROR_NO_MEM;
+ goto err;
+ }
+
+ memset(endpoint, 0, tmp);
+ for (i = 0; i < ifp->bNumEndpoints; i++) {
+ usbi_parse_descriptor(buffer, "bb", &header, 0);
+
+ if (header.bLength > size) {
+ usbi_err(ctx, "ran out of descriptors parsing");
+ r = LIBUSB_ERROR_IO;
+ goto err;
+ }
+
+ r = parse_endpoint(ctx, endpoint + i, buffer, size,
+ host_endian);
+ if (r < 0)
+ goto err;
+
+ buffer += r;
+ parsed += r;
+ size -= r;
+ }
+ }
+
+ /* We check to see if it's an alternate to this one */
+ ifp = (struct libusb_interface_descriptor *) buffer;
+ if (size < LIBUSB_DT_INTERFACE_SIZE ||
+ ifp->bDescriptorType != LIBUSB_DT_INTERFACE ||
+ !ifp->bAlternateSetting)
+ return parsed;
+ }
+
+ return parsed;
+err:
+ clear_interface(usb_interface);
+ return r;
+}
+
+static void clear_configuration(struct libusb_config_descriptor *config)
+{
+ if (config->interface) {
+ int i;
+ for (i = 0; i < config->bNumInterfaces; i++)
+ clear_interface((struct libusb_interface *)
+ config->interface + i);
+ free((void *) config->interface);
+ }
+ if (config->extra)
+ free((void *) config->extra);
+}
+
+static int parse_configuration(struct libusb_context *ctx,
+ struct libusb_config_descriptor *config, unsigned char *buffer,
+ int host_endian)
+{
+ int i;
+ int r;
+ int size;
+ int tmp;
+ struct usb_descriptor_header header;
+ struct libusb_interface *usb_interface;
+
+ usbi_parse_descriptor(buffer, "bbwbbbbb", config, host_endian);
+ size = config->wTotalLength;
+
+ if (config->bNumInterfaces > USB_MAXINTERFACES) {
+ usbi_err(ctx, "too many interfaces (%d)", config->bNumInterfaces);
+ return LIBUSB_ERROR_IO;
+ }
+
+ tmp = config->bNumInterfaces * sizeof(struct libusb_interface);
+ usb_interface = malloc(tmp);
+ config->interface = usb_interface;
+ if (!config->interface)
+ return LIBUSB_ERROR_NO_MEM;
+
+ memset(usb_interface, 0, tmp);
+ buffer += config->bLength;
+ size -= config->bLength;
+
+ config->extra = NULL;
+ config->extra_length = 0;
+
+ for (i = 0; i < config->bNumInterfaces; i++) {
+ int len;
+ unsigned char *begin;
+
+ /* Skip over the rest of the Class Specific or Vendor */
+ /* Specific descriptors */
+ begin = buffer;
+ while (size >= DESC_HEADER_LENGTH) {
+ usbi_parse_descriptor(buffer, "bb", &header, 0);
+
+ if ((header.bLength > size) ||
+ (header.bLength < DESC_HEADER_LENGTH)) {
+ usbi_err(ctx, "invalid descriptor length of %d",
+ header.bLength);
+ r = LIBUSB_ERROR_IO;
+ goto err;
+ }
+
+ /* If we find another "proper" descriptor then we're done */
+ if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
+ (header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
+ (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
+ (header.bDescriptorType == LIBUSB_DT_DEVICE))
+ break;
+
+ usbi_dbg("skipping descriptor 0x%x\n", header.bDescriptorType);
+ buffer += header.bLength;
+ size -= header.bLength;
+ }
+
+ /* Copy any unknown descriptors into a storage area for */
+ /* drivers to later parse */
+ len = (int)(buffer - begin);
+ if (len) {
+ /* FIXME: We should realloc and append here */
+ if (!config->extra_length) {
+ config->extra = malloc(len);
+ if (!config->extra) {
+ r = LIBUSB_ERROR_NO_MEM;
+ goto err;
+ }
+
+ memcpy((unsigned char *) config->extra, begin, len);
+ config->extra_length = len;
+ }
+ }
+
+ r = parse_interface(ctx, usb_interface + i, buffer, size, host_endian);
+ if (r < 0)
+ goto err;
+
+ buffer += r;
+ size -= r;
+ }
+
+ return size;
+
+err:
+ clear_configuration(config);
+ return r;
+}
+
+/** \ingroup desc
+ * Get the USB device descriptor for a given device.
+ *
+ * This is a non-blocking function; the device descriptor is cached in memory.
+ *
+ * \param dev the device
+ * \param desc output location for the descriptor data
+ * \returns 0 on success or a LIBUSB_ERROR code on failure
+ */
+int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev,
+ struct libusb_device_descriptor *desc)
+{
+ unsigned char raw_desc[DEVICE_DESC_LENGTH];
+ int host_endian = 0;
+ int r;
+
+ usbi_dbg("");
+ r = usbi_backend->get_device_descriptor(dev, raw_desc, &host_endian);
+ if (r < 0)
+ return r;
+
+ memcpy((unsigned char *) desc, raw_desc, sizeof(raw_desc));
+ if (!host_endian) {
+ desc->bcdUSB = libusb_le16_to_cpu(desc->bcdUSB);
+ desc->idVendor = libusb_le16_to_cpu(desc->idVendor);
+ desc->idProduct = libusb_le16_to_cpu(desc->idProduct);
+ desc->bcdDevice = libusb_le16_to_cpu(desc->bcdDevice);
+ }
+ return 0;
+}
+
+/** \ingroup desc
+ * Get the USB configuration descriptor for the currently active configuration.
+ * This is a non-blocking function which does not involve any requests being
+ * sent to the device.
+ *
+ * \param dev a device
+ * \param config output location for the USB configuration descriptor. Only
+ * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
+ * after use.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state
+ * \returns another LIBUSB_ERROR code on error
+ * \see libusb_get_config_descriptor
+ */
+int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev,
+ struct libusb_config_descriptor **config)
+{
+ struct libusb_config_descriptor *_config = malloc(sizeof(*_config));
+ unsigned char tmp[8];
+ unsigned char *buf = NULL;
+ int host_endian = 0;
+ int r;
+
+ usbi_dbg("");
+ if (!_config)
+ return LIBUSB_ERROR_NO_MEM;
+
+ r = usbi_backend->get_active_config_descriptor(dev, tmp, sizeof(tmp),
+ &host_endian);
+ if (r < 0)
+ goto err;
+
+ usbi_parse_descriptor(tmp, "bbw", _config, host_endian);
+ buf = malloc(_config->wTotalLength);
+ if (!buf) {
+ r = LIBUSB_ERROR_NO_MEM;
+ goto err;
+ }
+
+ r = usbi_backend->get_active_config_descriptor(dev, buf,
+ _config->wTotalLength, &host_endian);
+ if (r < 0)
+ goto err;
+
+ r = parse_configuration(dev->ctx, _config, buf, host_endian);
+ if (r < 0) {
+ usbi_err(dev->ctx, "parse_configuration failed with error %d", r);
+ goto err;
+ } else if (r > 0) {
+ usbi_warn(dev->ctx, "descriptor data still left");
+ }
+
+ free(buf);
+ *config = _config;
+ return 0;
+
+err:
+ free(_config);
+ if (buf)
+ free(buf);
+ return r;
+}
+
+/** \ingroup desc
+ * Get a USB configuration descriptor based on its index.
+ * This is a non-blocking function which does not involve any requests being
+ * sent to the device.
+ *
+ * \param dev a device
+ * \param config_index the index of the configuration you wish to retrieve
+ * \param config output location for the USB configuration descriptor. Only
+ * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
+ * after use.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
+ * \returns another LIBUSB_ERROR code on error
+ * \see libusb_get_active_config_descriptor()
+ * \see libusb_get_config_descriptor_by_value()
+ */
+int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
+ uint8_t config_index, struct libusb_config_descriptor **config)
+{
+ struct libusb_config_descriptor *_config;
+ unsigned char tmp[8];
+ unsigned char *buf = NULL;
+ int host_endian = 0;
+ int r;
+
+ usbi_dbg("index %d", config_index);
+ if (config_index >= dev->num_configurations)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ _config = malloc(sizeof(*_config));
+ if (!_config)
+ return LIBUSB_ERROR_NO_MEM;
+
+ r = usbi_backend->get_config_descriptor(dev, config_index, tmp,
+ sizeof(tmp), &host_endian);
+ if (r < 0)
+ goto err;
+
+ usbi_parse_descriptor(tmp, "bbw", _config, host_endian);
+ buf = malloc(_config->wTotalLength);
+ if (!buf) {
+ r = LIBUSB_ERROR_NO_MEM;
+ goto err;
+ }
+
+ host_endian = 0;
+ r = usbi_backend->get_config_descriptor(dev, config_index, buf,
+ _config->wTotalLength, &host_endian);
+ if (r < 0)
+ goto err;
+
+ r = parse_configuration(dev->ctx, _config, buf, host_endian);
+ if (r < 0) {
+ usbi_err(dev->ctx, "parse_configuration failed with error %d", r);
+ goto err;
+ } else if (r > 0) {
+ usbi_warn(dev->ctx, "descriptor data still left");
+ }
+
+ free(buf);
+ *config = _config;
+ return 0;
+
+err:
+ free(_config);
+ if (buf)
+ free(buf);
+ return r;
+}
+
+/* iterate through all configurations, returning the index of the configuration
+ * matching a specific bConfigurationValue in the idx output parameter, or -1
+ * if the config was not found.
+ * returns 0 or a LIBUSB_ERROR code
+ */
+int usbi_get_config_index_by_value(struct libusb_device *dev,
+ uint8_t bConfigurationValue, int *idx)
+{
+ uint8_t i;
+
+ usbi_dbg("value %d", bConfigurationValue);
+ 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),
+ &host_endian);
+ if (r < 0)
+ return r;
+ if (tmp[5] == bConfigurationValue) {
+ *idx = i;
+ return 0;
+ }
+ }
+
+ *idx = -1;
+ return 0;
+}
+
+/** \ingroup desc
+ * Get a USB configuration descriptor with a specific bConfigurationValue.
+ * This is a non-blocking function which does not involve any requests being
+ * sent to the device.
+ *
+ * \param dev a device
+ * \param bConfigurationValue the bConfigurationValue of the configuration you
+ * wish to retrieve
+ * \param config output location for the USB configuration descriptor. Only
+ * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
+ * after use.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
+ * \returns another LIBUSB_ERROR code on error
+ * \see libusb_get_active_config_descriptor()
+ * \see libusb_get_config_descriptor()
+ */
+int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev,
+ uint8_t bConfigurationValue, struct libusb_config_descriptor **config)
+{
+ int idx;
+ int r = usbi_get_config_index_by_value(dev, bConfigurationValue, &idx);
+ if (r < 0)
+ return r;
+ else if (idx == -1)
+ return LIBUSB_ERROR_NOT_FOUND;
+ else
+ return libusb_get_config_descriptor(dev, (uint8_t) idx, config);
+}
+
+/** \ingroup desc
+ * Free a configuration descriptor obtained from
+ * libusb_get_active_config_descriptor() or libusb_get_config_descriptor().
+ * It is safe to call this function with a NULL config parameter, in which
+ * case the function simply returns.
+ *
+ * \param config the configuration descriptor to free
+ */
+void API_EXPORTED libusb_free_config_descriptor(
+ struct libusb_config_descriptor *config)
+{
+ if (!config)
+ return;
+
+ clear_configuration(config);
+ free(config);
+}
+
+/** \ingroup desc
+ * Retrieve a string descriptor in C style ASCII.
+ *
+ * Wrapper around libusb_get_string_descriptor(). Uses the first language
+ * supported by the device.
+ *
+ * \param dev a device handle
+ * \param desc_index the index of the descriptor to retrieve
+ * \param data output buffer for ASCII string descriptor
+ * \param length size of data buffer
+ * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure
+ */
+int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev,
+ uint8_t desc_index, unsigned char *data, int length)
+{
+ unsigned char tbuf[255]; /* Some devices choke on size > 255 */
+ int r, si, di;
+ uint16_t langid;
+
+ /* Asking for the zero'th index is special - it returns a string
+ * descriptor that contains all the language IDs supported by the device.
+ * Typically there aren't many - often only one. The language IDs are 16
+ * bit numbers, and they start at the third byte in the descriptor. See
+ * USB 2.0 specification section 9.6.7 for more information. */
+ r = libusb_get_string_descriptor(dev, 0, 0, tbuf, sizeof(tbuf));
+ if (r < 0)
+ return r;
+
+ if (r < 4)
+ return LIBUSB_ERROR_IO;
+
+ langid = tbuf[2] | (tbuf[3] << 8);
+
+ r = libusb_get_string_descriptor(dev, desc_index, langid, tbuf,
+ sizeof(tbuf));
+ if (r < 0)
+ return r;
+
+ if (tbuf[1] != LIBUSB_DT_STRING)
+ return LIBUSB_ERROR_IO;
+
+ if (tbuf[0] > r)
+ return LIBUSB_ERROR_IO;
+
+ for (di = 0, si = 2; si < tbuf[0]; si += 2) {
+ if (di >= (length - 1))
+ break;
+
+ if (tbuf[si + 1]) /* high byte */
+ data[di++] = '?';
+ else
+ data[di++] = tbuf[si];
+ }
+
+ data[di] = 0;
+ return di;
+}
+
diff --git a/libusb-1.0/libusb/io.c b/libusb-1.0/libusb/io.c
new file mode 100644
index 0000000..d4f6f3d
--- /dev/null
+++ b/libusb-1.0/libusb/io.c
@@ -0,0 +1,2366 @@
+/*
+ * I/O functions for libusb
+ * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef USBI_TIMERFD_AVAILABLE
+#include <sys/timerfd.h>
+#endif
+
+#include "libusbi.h"
+
+/**
+ * \page io Synchronous and asynchronous device I/O
+ *
+ * \section intro Introduction
+ *
+ * If you're using libusb in your application, you're probably wanting to
+ * perform I/O with devices - you want to perform USB data transfers.
+ *
+ * libusb offers two separate interfaces for device I/O. This page aims to
+ * introduce the two in order to help you decide which one is more suitable
+ * for your application. You can also choose to use both interfaces in your
+ * application by considering each transfer on a case-by-case basis.
+ *
+ * Once you have read through the following discussion, you should consult the
+ * detailed API documentation pages for the details:
+ * - \ref syncio
+ * - \ref asyncio
+ *
+ * \section theory Transfers at a logical level
+ *
+ * At a logical level, USB transfers typically happen in two parts. For
+ * example, when reading data from a endpoint:
+ * -# A request for data is sent to the device
+ * -# Some time later, the incoming data is received by the host
+ *
+ * or when writing data to an endpoint:
+ *
+ * -# The data is sent to the device
+ * -# Some time later, the host receives acknowledgement from the device that
+ * the data has been transferred.
+ *
+ * There may be an indefinite delay between the two steps. Consider a
+ * fictional USB input device with a button that the user can press. In order
+ * to determine when the button is pressed, you would likely submit a request
+ * to read data on a bulk or interrupt endpoint and wait for data to arrive.
+ * Data will arrive when the button is pressed by the user, which is
+ * potentially hours later.
+ *
+ * libusb offers both a synchronous and an asynchronous interface to performing
+ * USB transfers. The main difference is that the synchronous interface
+ * combines both steps indicated above into a single function call, whereas
+ * the asynchronous interface separates them.
+ *
+ * \section sync The synchronous interface
+ *
+ * The synchronous I/O interface allows you to perform a USB transfer with
+ * a single function call. When the function call returns, the transfer has
+ * completed and you can parse the results.
+ *
+ * If you have used the libusb-0.1 before, this I/O style will seem familar to
+ * you. libusb-0.1 only offered a synchronous interface.
+ *
+ * In our input device example, to read button presses you might write code
+ * in the following style:
+\code
+unsigned char data[4];
+int actual_length,
+int r = libusb_bulk_transfer(handle, EP_IN, data, sizeof(data), &actual_length, 0);
+if (r == 0 && actual_length == sizeof(data)) {
+ // results of the transaction can now be found in the data buffer
+ // parse them here and report button press
+} else {
+ error();
+}
+\endcode
+ *
+ * The main advantage of this model is simplicity: you did everything with
+ * a single simple function call.
+ *
+ * However, this interface has its limitations. Your application will sleep
+ * inside libusb_bulk_transfer() until the transaction has completed. If it
+ * takes the user 3 hours to press the button, your application will be
+ * sleeping for that long. Execution will be tied up inside the library -
+ * the entire thread will be useless for that duration.
+ *
+ * Another issue is that by tieing up the thread with that single transaction
+ * there is no possibility of performing I/O with multiple endpoints and/or
+ * multiple devices simultaneously, unless you resort to creating one thread
+ * per transaction.
+ *
+ * Additionally, there is no opportunity to cancel the transfer after the
+ * request has been submitted.
+ *
+ * For details on how to use the synchronous API, see the
+ * \ref syncio "synchronous I/O API documentation" pages.
+ *
+ * \section async The asynchronous interface
+ *
+ * Asynchronous I/O is the most significant new feature in libusb-1.0.
+ * Although it is a more complex interface, it solves all the issues detailed
+ * above.
+ *
+ * Instead of providing which functions that block until the I/O has complete,
+ * libusb's asynchronous interface presents non-blocking functions which
+ * begin a transfer and then return immediately. Your application passes a
+ * callback function pointer to this non-blocking function, which libusb will
+ * call with the results of the transaction when it has completed.
+ *
+ * Transfers which have been submitted through the non-blocking functions
+ * can be cancelled with a separate function call.
+ *
+ * The non-blocking nature of this interface allows you to be simultaneously
+ * performing I/O to multiple endpoints on multiple devices, without having
+ * to use threads.
+ *
+ * This added flexibility does come with some complications though:
+ * - In the interest of being a lightweight library, libusb does not create
+ * threads and can only operate when your application is calling into it. Your
+ * application must call into libusb from it's main loop when events are ready
+ * to be handled, or you must use some other scheme to allow libusb to
+ * undertake whatever work needs to be done.
+ * - libusb also needs to be called into at certain fixed points in time in
+ * order to accurately handle transfer timeouts.
+ * - Memory handling becomes more complex. You cannot use stack memory unless
+ * the function with that stack is guaranteed not to return until the transfer
+ * callback has finished executing.
+ * - You generally lose some linearity from your code flow because submitting
+ * the transfer request is done in a separate function from where the transfer
+ * results are handled. This becomes particularly obvious when you want to
+ * submit a second transfer based on the results of an earlier transfer.
+ *
+ * Internally, libusb's synchronous interface is expressed in terms of function
+ * calls to the asynchronous interface.
+ *
+ * For details on how to use the asynchronous API, see the
+ * \ref asyncio "asynchronous I/O API" documentation pages.
+ */
+
+
+/**
+ * \page packetoverflow Packets and overflows
+ *
+ * \section packets Packet abstraction
+ *
+ * The USB specifications describe how data is transmitted in packets, with
+ * constraints on packet size defined by endpoint descriptors. The host must
+ * not send data payloads larger than the endpoint's maximum packet size.
+ *
+ * libusb and the underlying OS abstract out the packet concept, allowing you
+ * to request transfers of any size. Internally, the request will be divided
+ * up into correctly-sized packets. You do not have to be concerned with
+ * packet sizes, but there is one exception when considering overflows.
+ *
+ * \section overflow Bulk/interrupt transfer overflows
+ *
+ * When requesting data on a bulk endpoint, libusb requires you to supply a
+ * buffer and the maximum number of bytes of data that libusb can put in that
+ * buffer. However, the size of the buffer is not communicated to the device -
+ * the device is just asked to send any amount of data.
+ *
+ * There is no problem if the device sends an amount of data that is less than
+ * or equal to the buffer size. libusb reports this condition to you through
+ * the \ref libusb_transfer::actual_length "libusb_transfer.actual_length"
+ * field.
+ *
+ * Problems may occur if the device attempts to send more data than can fit in
+ * the buffer. libusb reports LIBUSB_TRANSFER_OVERFLOW for this condition but
+ * other behaviour is largely undefined: actual_length may or may not be
+ * accurate, the chunk of data that can fit in the buffer (before overflow)
+ * may or may not have been transferred.
+ *
+ * Overflows are nasty, but can be avoided. Even though you were told to
+ * ignore packets above, think about the lower level details: each transfer is
+ * split into packets (typically small, with a maximum size of 512 bytes).
+ * Overflows can only happen if the final packet in an incoming data transfer
+ * is smaller than the actual packet that the device wants to transfer.
+ * Therefore, you will never see an overflow if your transfer buffer size is a
+ * multiple of the endpoint's packet size: the final packet will either
+ * fill up completely or will be only partially filled.
+ */
+
+/**
+ * @defgroup asyncio Asynchronous device I/O
+ *
+ * This page details libusb's asynchronous (non-blocking) API for USB device
+ * I/O. This interface is very powerful but is also quite complex - you will
+ * need to read this page carefully to understand the necessary considerations
+ * and issues surrounding use of this interface. Simplistic applications
+ * may wish to consider the \ref syncio "synchronous I/O API" instead.
+ *
+ * The asynchronous interface is built around the idea of separating transfer
+ * submission and handling of transfer completion (the synchronous model
+ * combines both of these into one). There may be a long delay between
+ * submission and completion, however the asynchronous submission function
+ * is non-blocking so will return control to your application during that
+ * potentially long delay.
+ *
+ * \section asyncabstraction Transfer abstraction
+ *
+ * For the asynchronous I/O, libusb implements the concept of a generic
+ * transfer entity for all types of I/O (control, bulk, interrupt,
+ * isochronous). The generic transfer object must be treated slightly
+ * differently depending on which type of I/O you are performing with it.
+ *
+ * This is represented by the public libusb_transfer structure type.
+ *
+ * \section asynctrf Asynchronous transfers
+ *
+ * We can view asynchronous I/O as a 5 step process:
+ * -# <b>Allocation</b>: allocate a libusb_transfer
+ * -# <b>Filling</b>: populate the libusb_transfer instance with information
+ * about the transfer you wish to perform
+ * -# <b>Submission</b>: ask libusb to submit the transfer
+ * -# <b>Completion handling</b>: examine transfer results in the
+ * libusb_transfer structure
+ * -# <b>Deallocation</b>: clean up resources
+ *
+ *
+ * \subsection asyncalloc Allocation
+ *
+ * This step involves allocating memory for a USB transfer. This is the
+ * generic transfer object mentioned above. At this stage, the transfer
+ * is "blank" with no details about what type of I/O it will be used for.
+ *
+ * Allocation is done with the libusb_alloc_transfer() function. You must use
+ * this function rather than allocating your own transfers.
+ *
+ * \subsection asyncfill Filling
+ *
+ * This step is where you take a previously allocated transfer and fill it
+ * with information to determine the message type and direction, data buffer,
+ * callback function, etc.
+ *
+ * You can either fill the required fields yourself or you can use the
+ * helper functions: libusb_fill_control_transfer(), libusb_fill_bulk_transfer()
+ * and libusb_fill_interrupt_transfer().
+ *
+ * \subsection asyncsubmit Submission
+ *
+ * When you have allocated a transfer and filled it, you can submit it using
+ * libusb_submit_transfer(). This function returns immediately but can be
+ * regarded as firing off the I/O request in the background.
+ *
+ * \subsection asynccomplete Completion handling
+ *
+ * After a transfer has been submitted, one of four things can happen to it:
+ *
+ * - The transfer completes (i.e. some data was transferred)
+ * - The transfer has a timeout and the timeout expires before all data is
+ * transferred
+ * - The transfer fails due to an error
+ * - The transfer is cancelled
+ *
+ * Each of these will cause the user-specified transfer callback function to
+ * be invoked. It is up to the callback function to determine which of the
+ * above actually happened and to act accordingly.
+ *
+ * The user-specified callback is passed a pointer to the libusb_transfer
+ * structure which was used to setup and submit the transfer. At completion
+ * time, libusb has populated this structure with results of the transfer:
+ * success or failure reason, number of bytes of data transferred, etc. See
+ * the libusb_transfer structure documentation for more information.
+ *
+ * \subsection Deallocation
+ *
+ * When a transfer has completed (i.e. the callback function has been invoked),
+ * you are advised to free the transfer (unless you wish to resubmit it, see
+ * below). Transfers are deallocated with libusb_free_transfer().
+ *
+ * It is undefined behaviour to free a transfer which has not completed.
+ *
+ * \section asyncresubmit Resubmission
+ *
+ * You may be wondering why allocation, filling, and submission are all
+ * separated above where they could reasonably be combined into a single
+ * operation.
+ *
+ * The reason for separation is to allow you to resubmit transfers without
+ * having to allocate new ones every time. This is especially useful for
+ * common situations dealing with interrupt endpoints - you allocate one
+ * transfer, fill and submit it, and when it returns with results you just
+ * resubmit it for the next interrupt.
+ *
+ * \section asynccancel Cancellation
+ *
+ * Another advantage of using the asynchronous interface is that you have
+ * the ability to cancel transfers which have not yet completed. This is
+ * done by calling the libusb_cancel_transfer() function.
+ *
+ * libusb_cancel_transfer() is asynchronous/non-blocking in itself. When the
+ * cancellation actually completes, the transfer's callback function will
+ * be invoked, and the callback function should check the transfer status to
+ * determine that it was cancelled.
+ *
+ * Freeing the transfer after it has been cancelled but before cancellation
+ * has completed will result in undefined behaviour.
+ *
+ * When a transfer is cancelled, some of the data may have been transferred.
+ * libusb will communicate this to you in the transfer callback. Do not assume
+ * that no data was transferred.
+ *
+ * \section bulk_overflows Overflows on device-to-host bulk/interrupt endpoints
+ *
+ * If your device does not have predictable transfer sizes (or it misbehaves),
+ * your application may submit a request for data on an IN endpoint which is
+ * smaller than the data that the device wishes to send. In some circumstances
+ * this will cause an overflow, which is a nasty condition to deal with. See
+ * the \ref packetoverflow page for discussion.
+ *
+ * \section asyncctrl Considerations for control transfers
+ *
+ * The <tt>libusb_transfer</tt> structure is generic and hence does not
+ * include specific fields for the control-specific setup packet structure.
+ *
+ * In order to perform a control transfer, you must place the 8-byte setup
+ * packet at the start of the data buffer. To simplify this, you could
+ * cast the buffer pointer to type struct libusb_control_setup, or you can
+ * use the helper function libusb_fill_control_setup().
+ *
+ * The wLength field placed in the setup packet must be the length you would
+ * expect to be sent in the setup packet: the length of the payload that
+ * follows (or the expected maximum number of bytes to receive). However,
+ * the length field of the libusb_transfer object must be the length of
+ * the data buffer - i.e. it should be wLength <em>plus</em> the size of
+ * the setup packet (LIBUSB_CONTROL_SETUP_SIZE).
+ *
+ * If you use the helper functions, this is simplified for you:
+ * -# Allocate a buffer of size LIBUSB_CONTROL_SETUP_SIZE plus the size of the
+ * data you are sending/requesting.
+ * -# Call libusb_fill_control_setup() on the data buffer, using the transfer
+ * request size as the wLength value (i.e. do not include the extra space you
+ * allocated for the control setup).
+ * -# If this is a host-to-device transfer, place the data to be transferred
+ * in the data buffer, starting at offset LIBUSB_CONTROL_SETUP_SIZE.
+ * -# Call libusb_fill_control_transfer() to associate the data buffer with
+ * the transfer (and to set the remaining details such as callback and timeout).
+ * - Note that there is no parameter to set the length field of the transfer.
+ * The length is automatically inferred from the wLength field of the setup
+ * packet.
+ * -# Submit the transfer.
+ *
+ * The multi-byte control setup fields (wValue, wIndex and wLength) must
+ * be given in little-endian byte order (the endianness of the USB bus).
+ * Endianness conversion is transparently handled by
+ * libusb_fill_control_setup() which is documented to accept host-endian
+ * values.
+ *
+ * Further considerations are needed when handling transfer completion in
+ * your callback function:
+ * - As you might expect, the setup packet will still be sitting at the start
+ * of the data buffer.
+ * - If this was a device-to-host transfer, the received data will be sitting
+ * at offset LIBUSB_CONTROL_SETUP_SIZE into the buffer.
+ * - The actual_length field of the transfer structure is relative to the
+ * wLength of the setup packet, rather than the size of the data buffer. So,
+ * if your wLength was 4, your transfer's <tt>length</tt> was 12, then you
+ * should expect an <tt>actual_length</tt> of 4 to indicate that the data was
+ * transferred in entirity.
+ *
+ * To simplify parsing of setup packets and obtaining the data from the
+ * correct offset, you may wish to use the libusb_control_transfer_get_data()
+ * and libusb_control_transfer_get_setup() functions within your transfer
+ * callback.
+ *
+ * Even though control endpoints do not halt, a completed control transfer
+ * may have a LIBUSB_TRANSFER_STALL status code. This indicates the control
+ * request was not supported.
+ *
+ * \section asyncintr Considerations for interrupt transfers
+ *
+ * All interrupt transfers are performed using the polling interval presented
+ * by the bInterval value of the endpoint descriptor.
+ *
+ * \section asynciso Considerations for isochronous transfers
+ *
+ * Isochronous transfers are more complicated than transfers to
+ * non-isochronous endpoints.
+ *
+ * To perform I/O to an isochronous endpoint, allocate the transfer by calling
+ * libusb_alloc_transfer() with an appropriate number of isochronous packets.
+ *
+ * During filling, set \ref libusb_transfer::type "type" to
+ * \ref libusb_transfer_type::LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
+ * "LIBUSB_TRANSFER_TYPE_ISOCHRONOUS", and set
+ * \ref libusb_transfer::num_iso_packets "num_iso_packets" to a value less than
+ * or equal to the number of packets you requested during allocation.
+ * libusb_alloc_transfer() does not set either of these fields for you, given
+ * that you might not even use the transfer on an isochronous endpoint.
+ *
+ * Next, populate the length field for the first num_iso_packets entries in
+ * the \ref libusb_transfer::iso_packet_desc "iso_packet_desc" array. Section
+ * 5.6.3 of the USB2 specifications describe how the maximum isochronous
+ * packet length is determined by the wMaxPacketSize field in the endpoint
+ * descriptor.
+ * Two functions can help you here:
+ *
+ * - libusb_get_max_iso_packet_size() is an easy way to determine the max
+ * packet size for an isochronous endpoint. Note that the maximum packet
+ * size is actually the maximum number of bytes that can be transmitted in
+ * a single microframe, therefore this function multiplies the maximum number
+ * of bytes per transaction by the number of transaction opportunities per
+ * microframe.
+ * - libusb_set_iso_packet_lengths() assigns the same length to all packets
+ * within a transfer, which is usually what you want.
+ *
+ * For outgoing transfers, you'll obviously fill the buffer and populate the
+ * packet descriptors in hope that all the data gets transferred. For incoming
+ * transfers, you must ensure the buffer has sufficient capacity for
+ * the situation where all packets transfer the full amount of requested data.
+ *
+ * Completion handling requires some extra consideration. The
+ * \ref libusb_transfer::actual_length "actual_length" field of the transfer
+ * is meaningless and should not be examined; instead you must refer to the
+ * \ref libusb_iso_packet_descriptor::actual_length "actual_length" field of
+ * each individual packet.
+ *
+ * The \ref libusb_transfer::status "status" field of the transfer is also a
+ * little misleading:
+ * - If the packets were submitted and the isochronous data microframes
+ * completed normally, status will have value
+ * \ref libusb_transfer_status::LIBUSB_TRANSFER_COMPLETED
+ * "LIBUSB_TRANSFER_COMPLETED". Note that bus errors and software-incurred
+ * delays are not counted as transfer errors; the transfer.status field may
+ * indicate COMPLETED even if some or all of the packets failed. Refer to
+ * the \ref libusb_iso_packet_descriptor::status "status" field of each
+ * individual packet to determine packet failures.
+ * - The status field will have value
+ * \ref libusb_transfer_status::LIBUSB_TRANSFER_ERROR
+ * "LIBUSB_TRANSFER_ERROR" only when serious errors were encountered.
+ * - Other transfer status codes occur with normal behaviour.
+ *
+ * The data for each packet will be found at an offset into the buffer that
+ * can be calculated as if each prior packet completed in full. The
+ * libusb_get_iso_packet_buffer() and libusb_get_iso_packet_buffer_simple()
+ * functions may help you here.
+ *
+ * \section asyncmem Memory caveats
+ *
+ * In most circumstances, it is not safe to use stack memory for transfer
+ * buffers. This is because the function that fired off the asynchronous
+ * transfer may return before libusb has finished using the buffer, and when
+ * the function returns it's stack gets destroyed. This is true for both
+ * host-to-device and device-to-host transfers.
+ *
+ * The only case in which it is safe to use stack memory is where you can
+ * guarantee that the function owning the stack space for the buffer does not
+ * return until after the transfer's callback function has completed. In every
+ * other case, you need to use heap memory instead.
+ *
+ * \section asyncflags Fine control
+ *
+ * Through using this asynchronous interface, you may find yourself repeating
+ * a few simple operations many times. You can apply a bitwise OR of certain
+ * flags to a transfer to simplify certain things:
+ * - \ref libusb_transfer_flags::LIBUSB_TRANSFER_SHORT_NOT_OK
+ * "LIBUSB_TRANSFER_SHORT_NOT_OK" results in transfers which transferred
+ * less than the requested amount of data being marked with status
+ * \ref libusb_transfer_status::LIBUSB_TRANSFER_ERROR "LIBUSB_TRANSFER_ERROR"
+ * (they would normally be regarded as COMPLETED)
+ * - \ref libusb_transfer_flags::LIBUSB_TRANSFER_FREE_BUFFER
+ * "LIBUSB_TRANSFER_FREE_BUFFER" allows you to ask libusb to free the transfer
+ * buffer when freeing the transfer.
+ * - \ref libusb_transfer_flags::LIBUSB_TRANSFER_FREE_TRANSFER
+ * "LIBUSB_TRANSFER_FREE_TRANSFER" causes libusb to automatically free the
+ * transfer after the transfer callback returns.
+ *
+ * \section asyncevent Event handling
+ *
+ * In accordance of the aim of being a lightweight library, libusb does not
+ * create threads internally. This means that libusb code does not execute
+ * at any time other than when your application is calling a libusb function.
+ * However, an asynchronous model requires that libusb perform work at various
+ * points in time - namely processing the results of previously-submitted
+ * transfers and invoking the user-supplied callback function.
+ *
+ * This gives rise to the libusb_handle_events() function which your
+ * application must call into when libusb has work do to. This gives libusb
+ * the opportunity to reap pending transfers, invoke callbacks, etc.
+ *
+ * The first issue to discuss here is how your application can figure out
+ * when libusb has work to do. In fact, there are two naive options which
+ * do not actually require your application to know this:
+ * -# Periodically call libusb_handle_events() in non-blocking mode at fixed
+ * short intervals from your main loop
+ * -# Repeatedly call libusb_handle_events() in blocking mode from a dedicated
+ * thread.
+ *
+ * The first option is plainly not very nice, and will cause unnecessary
+ * CPU wakeups leading to increased power usage and decreased battery life.
+ * The second option is not very nice either, but may be the nicest option
+ * available to you if the "proper" approach can not be applied to your
+ * application (read on...).
+ *
+ * The recommended option is to integrate libusb with your application main
+ * event loop. libusb exposes a set of file descriptors which allow you to do
+ * this. Your main loop is probably already calling poll() or select() or a
+ * variant on a set of file descriptors for other event sources (e.g. keyboard
+ * button presses, mouse movements, network sockets, etc). You then add
+ * libusb's file descriptors to your poll()/select() calls, and when activity
+ * is detected on such descriptors you know it is time to call
+ * libusb_handle_events().
+ *
+ * There is one final event handling complication. libusb supports
+ * asynchronous transfers which time out after a specified time period, and
+ * this requires that libusb is called into at or after the timeout so that
+ * the timeout can be handled. So, in addition to considering libusb's file
+ * descriptors in your main event loop, you must also consider that libusb
+ * sometimes needs to be called into at fixed points in time even when there
+ * is no file descriptor activity.
+ *
+ * For the details on retrieving the set of file descriptors and determining
+ * the next timeout, see the \ref poll "polling and timing" API documentation.
+ */
+
+/**
+ * @defgroup poll Polling and timing
+ *
+ * This page documents libusb's functions for polling events and timing.
+ * These functions are only necessary for users of the
+ * \ref asyncio "asynchronous API". If you are only using the simpler
+ * \ref syncio "synchronous API" then you do not need to ever call these
+ * functions.
+ *
+ * The justification for the functionality described here has already been
+ * discussed in the \ref asyncevent "event handling" section of the
+ * asynchronous API documentation. In summary, libusb does not create internal
+ * threads for event processing and hence relies on your application calling
+ * into libusb at certain points in time so that pending events can be handled.
+ * In order to know precisely when libusb needs to be called into, libusb
+ * offers you a set of pollable file descriptors and information about when
+ * the next timeout expires.
+ *
+ * If you are using the asynchronous I/O API, you must take one of the two
+ * following options, otherwise your I/O will not complete.
+ *
+ * \section pollsimple The simple option
+ *
+ * If your application revolves solely around libusb and does not need to
+ * handle other event sources, you can have a program structure as follows:
+\code
+// initialize libusb
+// find and open device
+// maybe fire off some initial async I/O
+
+while (user_has_not_requested_exit)
+ libusb_handle_events(ctx);
+
+// clean up and exit
+\endcode
+ *
+ * With such a simple main loop, you do not have to worry about managing
+ * sets of file descriptors or handling timeouts. libusb_handle_events() will
+ * handle those details internally.
+ *
+ * \section pollmain The more advanced option
+ *
+ * \note This functionality is currently only available on Unix-like platforms.
+ * On Windows, libusb_get_pollfds() simply returns NULL. Exposing event sources
+ * on Windows will require some further thought and design.
+ *
+ * In more advanced applications, you will already have a main loop which
+ * is monitoring other event sources: network sockets, X11 events, mouse
+ * movements, etc. Through exposing a set of file descriptors, libusb is
+ * designed to cleanly integrate into such main loops.
+ *
+ * In addition to polling file descriptors for the other event sources, you
+ * take a set of file descriptors from libusb and monitor those too. When you
+ * detect activity on libusb's file descriptors, you call
+ * libusb_handle_events_timeout() in non-blocking mode.
+ *
+ * What's more, libusb may also need to handle events at specific moments in
+ * time. No file descriptor activity is generated at these times, so your
+ * own application needs to be continually aware of when the next one of these
+ * moments occurs (through calling libusb_get_next_timeout()), and then it
+ * needs to call libusb_handle_events_timeout() in non-blocking mode when
+ * these moments occur. This means that you need to adjust your
+ * poll()/select() timeout accordingly.
+ *
+ * libusb provides you with a set of file descriptors to poll and expects you
+ * to poll all of them, treating them as a single entity. The meaning of each
+ * file descriptor in the set is an internal implementation detail,
+ * platform-dependent and may vary from release to release. Don't try and
+ * interpret the meaning of the file descriptors, just do as libusb indicates,
+ * polling all of them at once.
+ *
+ * In pseudo-code, you want something that looks like:
+\code
+// initialise libusb
+
+libusb_get_pollfds(ctx)
+while (user has not requested application exit) {
+ libusb_get_next_timeout(ctx);
+ poll(on libusb file descriptors plus any other event sources of interest,
+ using a timeout no larger than the value libusb just suggested)
+ if (poll() indicated activity on libusb file descriptors)
+ libusb_handle_events_timeout(ctx, 0);
+ if (time has elapsed to or beyond the libusb timeout)
+ libusb_handle_events_timeout(ctx, 0);
+ // handle events from other sources here
+}
+
+// clean up and exit
+\endcode
+ *
+ * \subsection polltime Notes on time-based events
+ *
+ * The above complication with having to track time and call into libusb at
+ * specific moments is a bit of a headache. For maximum compatibility, you do
+ * need to write your main loop as above, but you may decide that you can
+ * restrict the supported platforms of your application and get away with
+ * a more simplistic scheme.
+ *
+ * These time-based event complications are \b not required on the following
+ * platforms:
+ * - Darwin
+ * - Linux, provided that the following version requirements are satisfied:
+ * - Linux v2.6.27 or newer, compiled with timerfd support
+ * - glibc v2.9 or newer
+ * - libusb v1.0.5 or newer
+ *
+ * Under these configurations, libusb_get_next_timeout() will \em always return
+ * 0, so your main loop can be simplified to:
+\code
+// initialise libusb
+
+libusb_get_pollfds(ctx)
+while (user has not requested application exit) {
+ poll(on libusb file descriptors plus any other event sources of interest,
+ using any timeout that you like)
+ if (poll() indicated activity on libusb file descriptors)
+ libusb_handle_events_timeout(ctx, 0);
+ // handle events from other sources here
+}
+
+// clean up and exit
+\endcode
+ *
+ * Do remember that if you simplify your main loop to the above, you will
+ * lose compatibility with some platforms (including legacy Linux platforms,
+ * and <em>any future platforms supported by libusb which may have time-based
+ * event requirements</em>). The resultant problems will likely appear as
+ * strange bugs in your application.
+ *
+ * You can use the libusb_pollfds_handle_timeouts() function to do a runtime
+ * check to see if it is safe to ignore the time-based event complications.
+ * If your application has taken the shortcut of ignoring libusb's next timeout
+ * in your main loop, then you are advised to check the return value of
+ * libusb_pollfds_handle_timeouts() during application startup, and to abort
+ * if the platform does suffer from these timing complications.
+ *
+ * \subsection fdsetchange Changes in the file descriptor set
+ *
+ * The set of file descriptors that libusb uses as event sources may change
+ * during the life of your application. Rather than having to repeatedly
+ * call libusb_get_pollfds(), you can set up notification functions for when
+ * the file descriptor set changes using libusb_set_pollfd_notifiers().
+ *
+ * \subsection mtissues Multi-threaded considerations
+ *
+ * Unfortunately, the situation is complicated further when multiple threads
+ * come into play. If two threads are monitoring the same file descriptors,
+ * the fact that only one thread will be woken up when an event occurs causes
+ * some headaches.
+ *
+ * The events lock, event waiters lock, and libusb_handle_events_locked()
+ * entities are added to solve these problems. You do not need to be concerned
+ * with these entities otherwise.
+ *
+ * See the extra documentation: \ref mtasync
+ */
+
+/** \page mtasync Multi-threaded applications and asynchronous I/O
+ *
+ * libusb is a thread-safe library, but extra considerations must be applied
+ * to applications which interact with libusb from multiple threads.
+ *
+ * The underlying issue that must be addressed is that all libusb I/O
+ * revolves around monitoring file descriptors through the poll()/select()
+ * system calls. This is directly exposed at the
+ * \ref asyncio "asynchronous interface" but it is important to note that the
+ * \ref syncio "synchronous interface" is implemented on top of the
+ * asynchonrous interface, therefore the same considerations apply.
+ *
+ * The issue is that if two or more threads are concurrently calling poll()
+ * or select() on libusb's file descriptors then only one of those threads
+ * will be woken up when an event arrives. The others will be completely
+ * oblivious that anything has happened.
+ *
+ * Consider the following pseudo-code, which submits an asynchronous transfer
+ * then waits for its completion. This style is one way you could implement a
+ * synchronous interface on top of the asynchronous interface (and libusb
+ * does something similar, albeit more advanced due to the complications
+ * explained on this page).
+ *
+\code
+void cb(struct libusb_transfer *transfer)
+{
+ int *completed = transfer->user_data;
+ *completed = 1;
+}
+
+void myfunc() {
+ struct libusb_transfer *transfer;
+ unsigned char buffer[LIBUSB_CONTROL_SETUP_SIZE];
+ int completed = 0;
+
+ transfer = libusb_alloc_transfer(0);
+ libusb_fill_control_setup(buffer,
+ LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, 0x04, 0x01, 0, 0);
+ libusb_fill_control_transfer(transfer, dev, buffer, cb, &completed, 1000);
+ libusb_submit_transfer(transfer);
+
+ while (!completed) {
+ poll(libusb file descriptors, 120*1000);
+ if (poll indicates activity)
+ libusb_handle_events_timeout(ctx, 0);
+ }
+ printf("completed!");
+ // other code here
+}
+\endcode
+ *
+ * Here we are <em>serializing</em> completion of an asynchronous event
+ * against a condition - the condition being completion of a specific transfer.
+ * The poll() loop has a long timeout to minimize CPU usage during situations
+ * when nothing is happening (it could reasonably be unlimited).
+ *
+ * If this is the only thread that is polling libusb's file descriptors, there
+ * is no problem: there is no danger that another thread will swallow up the
+ * event that we are interested in. On the other hand, if there is another
+ * thread polling the same descriptors, there is a chance that it will receive
+ * the event that we were interested in. In this situation, <tt>myfunc()</tt>
+ * will only realise that the transfer has completed on the next iteration of
+ * the loop, <em>up to 120 seconds later.</em> Clearly a two-minute delay is
+ * undesirable, and don't even think about using short timeouts to circumvent
+ * this issue!
+ *
+ * The solution here is to ensure that no two threads are ever polling the
+ * file descriptors at the same time. A naive implementation of this would
+ * impact the capabilities of the library, so libusb offers the scheme
+ * documented below to ensure no loss of functionality.
+ *
+ * Before we go any further, it is worth mentioning that all libusb-wrapped
+ * event handling procedures fully adhere to the scheme documented below.
+ * This includes libusb_handle_events() and all the synchronous I/O functions -
+ * libusb hides this headache from you. You do not need to worry about any
+ * of these issues if you stick to that level.
+ *
+ * The problem is when we consider the fact that libusb exposes file
+ * descriptors to allow for you to integrate asynchronous USB I/O into
+ * existing main loops, effectively allowing you to do some work behind
+ * libusb's back. If you do take libusb's file descriptors and pass them to
+ * poll()/select() yourself, you need to be aware of the associated issues.
+ *
+ * \section eventlock The events lock
+ *
+ * The first concept to be introduced is the events lock. The events lock
+ * is used to serialize threads that want to handle events, such that only
+ * one thread is handling events at any one time.
+ *
+ * You must take the events lock before polling libusb file descriptors,
+ * using libusb_lock_events(). You must release the lock as soon as you have
+ * aborted your poll()/select() loop, using libusb_unlock_events().
+ *
+ * \section threadwait Letting other threads do the work for you
+ *
+ * Although the events lock is a critical part of the solution, it is not
+ * enough on it's own. You might wonder if the following is sufficient...
+\code
+ libusb_lock_events(ctx);
+ while (!completed) {
+ poll(libusb file descriptors, 120*1000);
+ if (poll indicates activity)
+ libusb_handle_events_timeout(ctx, 0);
+ }
+ libusb_unlock_events(ctx);
+\endcode
+ * ...and the answer is that it is not. This is because the transfer in the
+ * code shown above may take a long time (say 30 seconds) to complete, and
+ * the lock is not released until the transfer is completed.
+ *
+ * Another thread with similar code that wants to do event handling may be
+ * working with a transfer that completes after a few milliseconds. Despite
+ * having such a quick completion time, the other thread cannot check that
+ * status of its transfer until the code above has finished (30 seconds later)
+ * due to contention on the lock.
+ *
+ * To solve this, libusb offers you a mechanism to determine when another
+ * thread is handling events. It also offers a mechanism to block your thread
+ * until the event handling thread has completed an event (and this mechanism
+ * does not involve polling of file descriptors).
+ *
+ * After determining that another thread is currently handling events, you
+ * obtain the <em>event waiters</em> lock using libusb_lock_event_waiters().
+ * You then re-check that some other thread is still handling events, and if
+ * so, you call libusb_wait_for_event().
+ *
+ * libusb_wait_for_event() puts your application to sleep until an event
+ * occurs, or until a thread releases the events lock. When either of these
+ * things happen, your thread is woken up, and should re-check the condition
+ * it was waiting on. It should also re-check that another thread is handling
+ * events, and if not, it should start handling events itself.
+ *
+ * This looks like the following, as pseudo-code:
+\code
+retry:
+if (libusb_try_lock_events(ctx) == 0) {
+ // we obtained the event lock: do our own event handling
+ while (!completed) {
+ if (!libusb_event_handling_ok(ctx)) {
+ libusb_unlock_events(ctx);
+ goto retry;
+ }
+ poll(libusb file descriptors, 120*1000);
+ if (poll indicates activity)
+ libusb_handle_events_locked(ctx, 0);
+ }
+ libusb_unlock_events(ctx);
+} else {
+ // another thread is doing event handling. wait for it to signal us that
+ // an event has completed
+ libusb_lock_event_waiters(ctx);
+
+ while (!completed) {
+ // now that we have the event waiters lock, double check that another
+ // thread is still handling events for us. (it may have ceased handling
+ // events in the time it took us to reach this point)
+ if (!libusb_event_handler_active(ctx)) {
+ // whoever was handling events is no longer doing so, try again
+ libusb_unlock_event_waiters(ctx);
+ goto retry;
+ }
+
+ libusb_wait_for_event(ctx, NULL);
+ }
+ libusb_unlock_event_waiters(ctx);
+}
+printf("completed!\n");
+\endcode
+ *
+ * A naive look at the above code may suggest that this can only support
+ * one event waiter (hence a total of 2 competing threads, the other doing
+ * event handling), because the event waiter seems to have taken the event
+ * waiters lock while waiting for an event. However, the system does support
+ * multiple event waiters, because libusb_wait_for_event() actually drops
+ * the lock while waiting, and reaquires it before continuing.
+ *
+ * We have now implemented code which can dynamically handle situations where
+ * nobody is handling events (so we should do it ourselves), and it can also
+ * handle situations where another thread is doing event handling (so we can
+ * piggyback onto them). It is also equipped to handle a combination of
+ * the two, for example, another thread is doing event handling, but for
+ * whatever reason it stops doing so before our condition is met, so we take
+ * over the event handling.
+ *
+ * Four functions were introduced in the above pseudo-code. Their importance
+ * should be apparent from the code shown above.
+ * -# libusb_try_lock_events() is a non-blocking function which attempts
+ * to acquire the events lock but returns a failure code if it is contended.
+ * -# libusb_event_handling_ok() checks that libusb is still happy for your
+ * thread to be performing event handling. Sometimes, libusb needs to
+ * interrupt the event handler, and this is how you can check if you have
+ * been interrupted. If this function returns 0, the correct behaviour is
+ * for you to give up the event handling lock, and then to repeat the cycle.
+ * The following libusb_try_lock_events() will fail, so you will become an
+ * events waiter. For more information on this, read \ref fullstory below.
+ * -# libusb_handle_events_locked() is a variant of
+ * libusb_handle_events_timeout() that you can call while holding the
+ * events lock. libusb_handle_events_timeout() itself implements similar
+ * logic to the above, so be sure not to call it when you are
+ * "working behind libusb's back", as is the case here.
+ * -# libusb_event_handler_active() determines if someone is currently
+ * holding the events lock
+ *
+ * You might be wondering why there is no function to wake up all threads
+ * blocked on libusb_wait_for_event(). This is because libusb can do this
+ * internally: it will wake up all such threads when someone calls
+ * libusb_unlock_events() or when a transfer completes (at the point after its
+ * callback has returned).
+ *
+ * \subsection fullstory The full story
+ *
+ * The above explanation should be enough to get you going, but if you're
+ * really thinking through the issues then you may be left with some more
+ * questions regarding libusb's internals. If you're curious, read on, and if
+ * not, skip to the next section to avoid confusing yourself!
+ *
+ * The immediate question that may spring to mind is: what if one thread
+ * modifies the set of file descriptors that need to be polled while another
+ * thread is doing event handling?
+ *
+ * There are 2 situations in which this may happen.
+ * -# libusb_open() will add another file descriptor to the poll set,
+ * therefore it is desirable to interrupt the event handler so that it
+ * restarts, picking up the new descriptor.
+ * -# libusb_close() will remove a file descriptor from the poll set. There
+ * are all kinds of race conditions that could arise here, so it is
+ * important that nobody is doing event handling at this time.
+ *
+ * libusb handles these issues internally, so application developers do not
+ * have to stop their event handlers while opening/closing devices. Here's how
+ * it works, focusing on the libusb_close() situation first:
+ *
+ * -# During initialization, libusb opens an internal pipe, and it adds the read
+ * end of this pipe to the set of file descriptors to be polled.
+ * -# During libusb_close(), libusb writes some dummy data on this control pipe.
+ * This immediately interrupts the event handler. libusb also records
+ * internally that it is trying to interrupt event handlers for this
+ * high-priority event.
+ * -# At this point, some of the functions described above start behaving
+ * differently:
+ * - libusb_event_handling_ok() starts returning 1, indicating that it is NOT
+ * OK for event handling to continue.
+ * - libusb_try_lock_events() starts returning 1, indicating that another
+ * thread holds the event handling lock, even if the lock is uncontended.
+ * - libusb_event_handler_active() starts returning 1, indicating that
+ * another thread is doing event handling, even if that is not true.
+ * -# The above changes in behaviour result in the event handler stopping and
+ * giving up the events lock very quickly, giving the high-priority
+ * libusb_close() operation a "free ride" to acquire the events lock. All
+ * threads that are competing to do event handling become event waiters.
+ * -# With the events lock held inside libusb_close(), libusb can safely remove
+ * a file descriptor from the poll set, in the safety of knowledge that
+ * nobody is polling those descriptors or trying to access the poll set.
+ * -# After obtaining the events lock, the close operation completes very
+ * quickly (usually a matter of milliseconds) and then immediately releases
+ * the events lock.
+ * -# At the same time, the behaviour of libusb_event_handling_ok() and friends
+ * reverts to the original, documented behaviour.
+ * -# The release of the events lock causes the threads that are waiting for
+ * events to be woken up and to start competing to become event handlers
+ * again. One of them will succeed; it will then re-obtain the list of poll
+ * descriptors, and USB I/O will then continue as normal.
+ *
+ * libusb_open() is similar, and is actually a more simplistic case. Upon a
+ * call to libusb_open():
+ *
+ * -# The device is opened and a file descriptor is added to the poll set.
+ * -# libusb sends some dummy data on the control pipe, and records that it
+ * is trying to modify the poll descriptor set.
+ * -# The event handler is interrupted, and the same behaviour change as for
+ * libusb_close() takes effect, causing all event handling threads to become
+ * event waiters.
+ * -# The libusb_open() implementation takes its free ride to the events lock.
+ * -# Happy that it has successfully paused the events handler, libusb_open()
+ * releases the events lock.
+ * -# The event waiter threads are all woken up and compete to become event
+ * handlers again. The one that succeeds will obtain the list of poll
+ * descriptors again, which will include the addition of the new device.
+ *
+ * \subsection concl Closing remarks
+ *
+ * The above may seem a little complicated, but hopefully I have made it clear
+ * why such complications are necessary. Also, do not forget that this only
+ * applies to applications that take libusb's file descriptors and integrate
+ * them into their own polling loops.
+ *
+ * You may decide that it is OK for your multi-threaded application to ignore
+ * some of the rules and locks detailed above, because you don't think that
+ * two threads can ever be polling the descriptors at the same time. If that
+ * is the case, then that's good news for you because you don't have to worry.
+ * But be careful here; remember that the synchronous I/O functions do event
+ * handling internally. If you have one thread doing event handling in a loop
+ * (without implementing the rules and locking semantics documented above)
+ * and another trying to send a synchronous USB transfer, you will end up with
+ * two threads monitoring the same descriptors, and the above-described
+ * undesirable behaviour occuring. The solution is for your polling thread to
+ * play by the rules; the synchronous I/O functions do so, and this will result
+ * in them getting along in perfect harmony.
+ *
+ * If you do have a dedicated thread doing event handling, it is perfectly
+ * legal for it to take the event handling lock for long periods of time. Any
+ * synchronous I/O functions you call from other threads will transparently
+ * fall back to the "event waiters" mechanism detailed above. The only
+ * consideration that your event handling thread must apply is the one related
+ * to libusb_event_handling_ok(): you must call this before every poll(), and
+ * give up the events lock if instructed.
+ */
+
+int usbi_io_init(struct libusb_context *ctx)
+{
+ int r;
+
+ usbi_mutex_init(&ctx->flying_transfers_lock, NULL);
+ usbi_mutex_init(&ctx->pollfds_lock, NULL);
+ usbi_mutex_init(&ctx->pollfd_modify_lock, NULL);
+ usbi_mutex_init(&ctx->events_lock, NULL);
+ usbi_mutex_init(&ctx->event_waiters_lock, NULL);
+ usbi_cond_init(&ctx->event_waiters_cond, NULL);
+ list_init(&ctx->flying_transfers);
+ list_init(&ctx->pollfds);
+
+ /* FIXME should use an eventfd on kernels that support it */
+ r = usbi_pipe(ctx->ctrl_pipe);
+ if (r < 0) {
+ r = LIBUSB_ERROR_OTHER;
+ goto err;
+ }
+
+ r = usbi_add_pollfd(ctx, ctx->ctrl_pipe[0], POLLIN);
+ if (r < 0)
+ goto err_close_pipe;
+
+#ifdef USBI_TIMERFD_AVAILABLE
+ ctx->timerfd = timerfd_create(usbi_backend->get_timerfd_clockid(),
+ TFD_NONBLOCK);
+ if (ctx->timerfd >= 0) {
+ usbi_dbg("using timerfd for timeouts");
+ r = usbi_add_pollfd(ctx, ctx->timerfd, POLLIN);
+ if (r < 0) {
+ usbi_remove_pollfd(ctx, ctx->ctrl_pipe[0]);
+ close(ctx->timerfd);
+ goto err_close_pipe;
+ }
+ } else {
+ usbi_dbg("timerfd not available (code %d error %d)", ctx->timerfd, errno);
+ ctx->timerfd = -1;
+ }
+#endif
+
+ return 0;
+
+err_close_pipe:
+ usbi_close(ctx->ctrl_pipe[0]);
+ usbi_close(ctx->ctrl_pipe[1]);
+err:
+ usbi_mutex_destroy(&ctx->flying_transfers_lock);
+ usbi_mutex_destroy(&ctx->pollfds_lock);
+ usbi_mutex_destroy(&ctx->pollfd_modify_lock);
+ usbi_mutex_destroy(&ctx->events_lock);
+ usbi_mutex_destroy(&ctx->event_waiters_lock);
+ usbi_cond_destroy(&ctx->event_waiters_cond);
+ return r;
+}
+
+void usbi_io_exit(struct libusb_context *ctx)
+{
+ usbi_remove_pollfd(ctx, ctx->ctrl_pipe[0]);
+ usbi_close(ctx->ctrl_pipe[0]);
+ usbi_close(ctx->ctrl_pipe[1]);
+#ifdef USBI_TIMERFD_AVAILABLE
+ if (usbi_using_timerfd(ctx)) {
+ usbi_remove_pollfd(ctx, ctx->timerfd);
+ close(ctx->timerfd);
+ }
+#endif
+ usbi_mutex_destroy(&ctx->flying_transfers_lock);
+ usbi_mutex_destroy(&ctx->pollfds_lock);
+ usbi_mutex_destroy(&ctx->pollfd_modify_lock);
+ usbi_mutex_destroy(&ctx->events_lock);
+ usbi_mutex_destroy(&ctx->event_waiters_lock);
+ usbi_cond_destroy(&ctx->event_waiters_cond);
+}
+
+static int calculate_timeout(struct usbi_transfer *transfer)
+{
+ int r;
+ struct timespec current_time;
+ unsigned int timeout =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout;
+
+ if (!timeout)
+ return 0;
+
+ 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);
+ return r;
+ }
+
+ current_time.tv_sec += timeout / 1000;
+ current_time.tv_nsec += (timeout % 1000) * 1000000;
+
+ if (current_time.tv_nsec > 1000000000) {
+ current_time.tv_nsec -= 1000000000;
+ current_time.tv_sec++;
+ }
+
+ TIMESPEC_TO_TIMEVAL(&transfer->timeout, &current_time);
+ return 0;
+}
+
+/* add a transfer to the (timeout-sorted) active transfers list.
+ * returns 1 if the transfer has a timeout and it is the timeout next to
+ * expire */
+static int add_to_flying_list(struct usbi_transfer *transfer)
+{
+ struct usbi_transfer *cur;
+ struct timeval *timeout = &transfer->timeout;
+ struct libusb_context *ctx = ITRANSFER_CTX(transfer);
+ int r = 0;
+ int first = 1;
+
+ usbi_mutex_lock(&ctx->flying_transfers_lock);
+
+ /* if we have no other flying transfers, start the list with this one */
+ if (list_empty(&ctx->flying_transfers)) {
+ list_add(&transfer->list, &ctx->flying_transfers);
+ if (timerisset(timeout))
+ r = 1;
+ goto out;
+ }
+
+ /* if we have infinite timeout, append to end of list */
+ if (!timerisset(timeout)) {
+ list_add_tail(&transfer->list, &ctx->flying_transfers);
+ goto out;
+ }
+
+ /* otherwise, find appropriate place in list */
+ list_for_each_entry(cur, &ctx->flying_transfers, list, struct usbi_transfer) {
+ /* find first timeout that occurs after the transfer in question */
+ struct timeval *cur_tv = &cur->timeout;
+
+ if (!timerisset(cur_tv) || (cur_tv->tv_sec > timeout->tv_sec) ||
+ (cur_tv->tv_sec == timeout->tv_sec &&
+ cur_tv->tv_usec > timeout->tv_usec)) {
+ list_add_tail(&transfer->list, &cur->list);
+ r = first;
+ goto out;
+ }
+ first = 0;
+ }
+
+ /* otherwise we need to be inserted at the end */
+ list_add_tail(&transfer->list, &ctx->flying_transfers);
+out:
+ usbi_mutex_unlock(&ctx->flying_transfers_lock);
+ return r;
+}
+
+/** \ingroup asyncio
+ * Allocate a libusb transfer with a specified number of isochronous packet
+ * descriptors. The returned transfer is pre-initialized for you. When the new
+ * transfer is no longer needed, it should be freed with
+ * libusb_free_transfer().
+ *
+ * Transfers intended for non-isochronous endpoints (e.g. control, bulk,
+ * interrupt) should specify an iso_packets count of zero.
+ *
+ * For transfers intended for isochronous endpoints, specify an appropriate
+ * number of packet descriptors to be allocated as part of the transfer.
+ * The returned transfer is not specially initialized for isochronous I/O;
+ * you are still required to set the
+ * \ref libusb_transfer::num_iso_packets "num_iso_packets" and
+ * \ref libusb_transfer::type "type" fields accordingly.
+ *
+ * It is safe to allocate a transfer with some isochronous packets and then
+ * 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
+ * \returns a newly allocated transfer, or NULL on error
+ */
+DEFAULT_VISIBILITY
+struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(
+ int iso_packets)
+{
+ size_t os_alloc_size = usbi_backend->transfer_priv_size
+ + (usbi_backend->add_iso_packet_size * iso_packets);
+ size_t alloc_size = sizeof(struct usbi_transfer)
+ + sizeof(struct libusb_transfer)
+ + (sizeof(struct libusb_iso_packet_descriptor) * iso_packets)
+ + os_alloc_size;
+ struct usbi_transfer *itransfer = malloc(alloc_size);
+ if (!itransfer)
+ return NULL;
+
+ memset(itransfer, 0, alloc_size);
+ itransfer->num_iso_packets = iso_packets;
+ usbi_mutex_init(&itransfer->lock, NULL);
+ return __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+}
+
+/** \ingroup asyncio
+ * Free a transfer structure. This should be called for all transfers
+ * allocated with libusb_alloc_transfer().
+ *
+ * If the \ref libusb_transfer_flags::LIBUSB_TRANSFER_FREE_BUFFER
+ * "LIBUSB_TRANSFER_FREE_BUFFER" flag is set and the transfer buffer is
+ * non-NULL, this function will also free the transfer buffer using the
+ * standard system memory allocator (e.g. free()).
+ *
+ * It is legal to call this function with a NULL transfer. In this case,
+ * the function will simply return safely.
+ *
+ * It is not legal to free an active transfer (one which has been submitted
+ * and has not yet completed).
+ *
+ * \param transfer the transfer to free
+ */
+void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer)
+{
+ struct usbi_transfer *itransfer;
+ if (!transfer)
+ return;
+
+ if (transfer->flags & LIBUSB_TRANSFER_FREE_BUFFER && transfer->buffer)
+ free(transfer->buffer);
+
+ itransfer = __LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
+ usbi_mutex_destroy(&itransfer->lock);
+ free(itransfer);
+}
+
+/** \ingroup asyncio
+ * Submit a transfer. This function will fire off the USB transfer and then
+ * return immediately.
+ *
+ * \param transfer the transfer to submit
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns LIBUSB_ERROR_BUSY if the transfer has already been submitted.
+ * \returns another LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer)
+{
+ struct libusb_context *ctx = TRANSFER_CTX(transfer);
+ struct usbi_transfer *itransfer =
+ __LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
+ int r;
+ int first;
+
+ usbi_mutex_lock(&itransfer->lock);
+ itransfer->transferred = 0;
+ itransfer->flags = 0;
+ r = calculate_timeout(itransfer);
+ if (r < 0) {
+ r = LIBUSB_ERROR_OTHER;
+ goto out;
+ }
+
+ first = add_to_flying_list(itransfer);
+ r = usbi_backend->submit_transfer(itransfer);
+ if (r) {
+ usbi_mutex_lock(&ctx->flying_transfers_lock);
+ list_del(&itransfer->list);
+ usbi_mutex_unlock(&ctx->flying_transfers_lock);
+ }
+#ifdef USBI_TIMERFD_AVAILABLE
+ else if (first && usbi_using_timerfd(ctx)) {
+ /* if this transfer has the lowest timeout of all active transfers,
+ * rearm the timerfd with this transfer's timeout */
+ const struct itimerspec it = { {0, 0},
+ { itransfer->timeout.tv_sec, itransfer->timeout.tv_usec * 1000 } };
+ usbi_dbg("arm timerfd for timeout in %dms (first in line)", transfer->timeout);
+ r = timerfd_settime(ctx->timerfd, TFD_TIMER_ABSTIME, &it, NULL);
+ if (r < 0)
+ r = LIBUSB_ERROR_OTHER;
+ }
+#endif
+
+out:
+ usbi_mutex_unlock(&itransfer->lock);
+ return r;
+}
+
+/** \ingroup asyncio
+ * Asynchronously cancel a previously submitted transfer.
+ * This function returns immediately, but this does not indicate cancellation
+ * is complete. Your callback function will be invoked at some later time
+ * with a transfer status of
+ * \ref libusb_transfer_status::LIBUSB_TRANSFER_CANCELLED
+ * "LIBUSB_TRANSFER_CANCELLED."
+ *
+ * \param transfer the transfer to cancel
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the transfer is already complete or
+ * cancelled.
+ * \returns a LIBUSB_ERROR code on failure
+ */
+int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer)
+{
+ struct usbi_transfer *itransfer =
+ __LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
+ int r;
+
+ usbi_dbg("");
+ usbi_mutex_lock(&itransfer->lock);
+ r = usbi_backend->cancel_transfer(itransfer);
+ if (r < 0)
+ usbi_err(TRANSFER_CTX(transfer),
+ "cancel transfer failed error %d", r);
+ usbi_mutex_unlock(&itransfer->lock);
+ return r;
+}
+
+#ifdef USBI_TIMERFD_AVAILABLE
+static int disarm_timerfd(struct libusb_context *ctx)
+{
+ const struct itimerspec disarm_timer = { { 0, 0 }, { 0, 0 } };
+ int r;
+
+ usbi_dbg("");
+ r = timerfd_settime(ctx->timerfd, 0, &disarm_timer, NULL);
+ if (r < 0)
+ return LIBUSB_ERROR_OTHER;
+ else
+ return 0;
+}
+
+/* iterates through the flying transfers, and rearms the timerfd based on the
+ * next upcoming timeout.
+ * must be called with flying_list locked.
+ * returns 0 if there was no timeout to arm, 1 if the next timeout was armed,
+ * or a LIBUSB_ERROR code on failure.
+ */
+static int arm_timerfd_for_next_timeout(struct libusb_context *ctx)
+{
+ struct usbi_transfer *transfer;
+
+ list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+ struct timeval *cur_tv = &transfer->timeout;
+
+ /* if we've reached transfers of infinite timeout, then we have no
+ * arming to do */
+ if (!timerisset(cur_tv))
+ return 0;
+
+ /* act on first transfer that is not already cancelled */
+ if (!(transfer->flags & USBI_TRANSFER_TIMED_OUT)) {
+ int r;
+ const struct itimerspec it = { {0, 0},
+ { cur_tv->tv_sec, cur_tv->tv_usec * 1000 } };
+ usbi_dbg("next timeout originally %dms", __USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout);
+ r = timerfd_settime(ctx->timerfd, TFD_TIMER_ABSTIME, &it, NULL);
+ if (r < 0)
+ return LIBUSB_ERROR_OTHER;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+#else
+static int disarm_timerfd(struct libusb_context *ctx)
+{
+ return 0;
+}
+static int arm_timerfd_for_next_timeout(struct libusb_context *ctx)
+{
+ return 0;
+}
+#endif
+
+/* Handle completion of a transfer (completion might be an error condition).
+ * This will invoke the user-supplied callback function, which may end up
+ * freeing the transfer. Therefore you cannot use the transfer structure
+ * after calling this function, and you should free all backend-specific
+ * data before calling it.
+ * Do not call this function with the usbi_transfer lock held. User-specified
+ * callback functions may attempt to directly resubmit the transfer, which
+ * will attempt to take the lock. */
+int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
+ enum libusb_transfer_status status)
+{
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = TRANSFER_CTX(transfer);
+ uint8_t flags;
+ int r;
+
+ /* FIXME: could be more intelligent with the timerfd here. we don't need
+ * to disarm the timerfd if there was no timer running, and we only need
+ * to rearm the timerfd if the transfer that expired was the one with
+ * the shortest timeout. */
+
+ usbi_mutex_lock(&ctx->flying_transfers_lock);
+ list_del(&itransfer->list);
+ r = arm_timerfd_for_next_timeout(ctx);
+ usbi_mutex_unlock(&ctx->flying_transfers_lock);
+
+ if (r < 0) {
+ return r;
+ } else if (r == 0) {
+ r = disarm_timerfd(ctx);
+ if (r < 0)
+ return r;
+ }
+
+ if (status == LIBUSB_TRANSFER_COMPLETED
+ && transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
+ int rqlen = transfer->length;
+ if (transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL)
+ rqlen -= LIBUSB_CONTROL_SETUP_SIZE;
+ if (rqlen != itransfer->transferred) {
+ usbi_dbg("interpreting short transfer as error");
+ status = LIBUSB_TRANSFER_ERROR;
+ }
+ }
+
+ flags = transfer->flags;
+ transfer->status = status;
+ transfer->actual_length = itransfer->transferred;
+ if (transfer->callback)
+ transfer->callback(transfer);
+ /* transfer might have been freed by the above call, do not use from
+ * this point. */
+ if (flags & LIBUSB_TRANSFER_FREE_TRANSFER)
+ libusb_free_transfer(transfer);
+ usbi_mutex_lock(&ctx->event_waiters_lock);
+ usbi_cond_broadcast(&ctx->event_waiters_cond);
+ usbi_mutex_unlock(&ctx->event_waiters_lock);
+ return 0;
+}
+
+/* Similar to usbi_handle_transfer_completion() but exclusively for transfers
+ * that were asynchronously cancelled. The same concerns w.r.t. freeing of
+ * transfers exist here.
+ * Do not call this function with the usbi_transfer lock held. User-specified
+ * callback functions may attempt to directly resubmit the transfer, which
+ * will attempt to take the lock. */
+int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer)
+{
+ /* if the URB was cancelled due to timeout, report timeout to the user */
+ if (transfer->flags & USBI_TRANSFER_TIMED_OUT) {
+ usbi_dbg("detected timeout cancellation");
+ return usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_TIMED_OUT);
+ }
+
+ /* otherwise its a normal async cancel */
+ return usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_CANCELLED);
+}
+
+/** \ingroup poll
+ * Attempt to acquire the event handling lock. This lock is used to ensure that
+ * only one thread is monitoring libusb event sources at any one time.
+ *
+ * You only need to use this lock if you are developing an application
+ * which calls poll() or select() on libusb's file descriptors directly.
+ * If you stick to libusb's event handling loop functions (e.g.
+ * libusb_handle_events()) then you do not need to be concerned with this
+ * locking.
+ *
+ * While holding this lock, you are trusted to actually be handling events.
+ * If you are no longer handling events, you must call libusb_unlock_events()
+ * as soon as possible.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \returns 0 if the lock was obtained successfully
+ * \returns 1 if the lock was not obtained (i.e. another thread holds the lock)
+ * \see \ref mtasync
+ */
+int API_EXPORTED libusb_try_lock_events(libusb_context *ctx)
+{
+ int r;
+ USBI_GET_CONTEXT(ctx);
+
+ /* is someone else waiting to modify poll fds? if so, don't let this thread
+ * start event handling */
+ usbi_mutex_lock(&ctx->pollfd_modify_lock);
+ r = ctx->pollfd_modify;
+ usbi_mutex_unlock(&ctx->pollfd_modify_lock);
+ if (r) {
+ usbi_dbg("someone else is modifying poll fds");
+ return 1;
+ }
+
+ r = usbi_mutex_trylock(&ctx->events_lock);
+ if (r)
+ return 1;
+
+ ctx->event_handler_active = 1;
+ return 0;
+}
+
+/** \ingroup poll
+ * Acquire the event handling lock, blocking until successful acquisition if
+ * it is contended. This lock is used to ensure that only one thread is
+ * monitoring libusb event sources at any one time.
+ *
+ * You only need to use this lock if you are developing an application
+ * which calls poll() or select() on libusb's file descriptors directly.
+ * If you stick to libusb's event handling loop functions (e.g.
+ * libusb_handle_events()) then you do not need to be concerned with this
+ * locking.
+ *
+ * While holding this lock, you are trusted to actually be handling events.
+ * If you are no longer handling events, you must call libusb_unlock_events()
+ * as soon as possible.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \see \ref mtasync
+ */
+void API_EXPORTED libusb_lock_events(libusb_context *ctx)
+{
+ USBI_GET_CONTEXT(ctx);
+ usbi_mutex_lock(&ctx->events_lock);
+ ctx->event_handler_active = 1;
+}
+
+/** \ingroup poll
+ * Release the lock previously acquired with libusb_try_lock_events() or
+ * libusb_lock_events(). Releasing this lock will wake up any threads blocked
+ * on libusb_wait_for_event().
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \see \ref mtasync
+ */
+void API_EXPORTED libusb_unlock_events(libusb_context *ctx)
+{
+ USBI_GET_CONTEXT(ctx);
+ ctx->event_handler_active = 0;
+ usbi_mutex_unlock(&ctx->events_lock);
+
+ /* FIXME: perhaps we should be a bit more efficient by not broadcasting
+ * the availability of the events lock when we are modifying pollfds
+ * (check ctx->pollfd_modify)? */
+ usbi_mutex_lock(&ctx->event_waiters_lock);
+ usbi_cond_broadcast(&ctx->event_waiters_cond);
+ usbi_mutex_unlock(&ctx->event_waiters_lock);
+}
+
+/** \ingroup poll
+ * Determine if it is still OK for this thread to be doing event handling.
+ *
+ * Sometimes, libusb needs to temporarily pause all event handlers, and this
+ * is the function you should use before polling file descriptors to see if
+ * this is the case.
+ *
+ * If this function instructs your thread to give up the events lock, you
+ * should just continue the usual logic that is documented in \ref mtasync.
+ * On the next iteration, your thread will fail to obtain the events lock,
+ * and will hence become an event waiter.
+ *
+ * This function should be called while the events lock is held: you don't
+ * need to worry about the results of this function if your thread is not
+ * the current event handler.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \returns 1 if event handling can start or continue
+ * \returns 0 if this thread must give up the events lock
+ * \see \ref fullstory "Multi-threaded I/O: the full story"
+ */
+int API_EXPORTED libusb_event_handling_ok(libusb_context *ctx)
+{
+ int r;
+ USBI_GET_CONTEXT(ctx);
+
+ /* is someone else waiting to modify poll fds? if so, don't let this thread
+ * continue event handling */
+ usbi_mutex_lock(&ctx->pollfd_modify_lock);
+ r = ctx->pollfd_modify;
+ usbi_mutex_unlock(&ctx->pollfd_modify_lock);
+ if (r) {
+ usbi_dbg("someone else is modifying poll fds");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/** \ingroup poll
+ * Determine if an active thread is handling events (i.e. if anyone is holding
+ * the event handling lock).
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \returns 1 if a thread is handling events
+ * \returns 0 if there are no threads currently handling events
+ * \see \ref mtasync
+ */
+int API_EXPORTED libusb_event_handler_active(libusb_context *ctx)
+{
+ int r;
+ USBI_GET_CONTEXT(ctx);
+
+ /* is someone else waiting to modify poll fds? if so, don't let this thread
+ * start event handling -- indicate that event handling is happening */
+ usbi_mutex_lock(&ctx->pollfd_modify_lock);
+ r = ctx->pollfd_modify;
+ usbi_mutex_unlock(&ctx->pollfd_modify_lock);
+ if (r) {
+ usbi_dbg("someone else is modifying poll fds");
+ return 1;
+ }
+
+ return ctx->event_handler_active;
+}
+
+/** \ingroup poll
+ * Acquire the event waiters lock. This lock is designed to be obtained under
+ * the situation where you want to be aware when events are completed, but
+ * some other thread is event handling so calling libusb_handle_events() is not
+ * allowed.
+ *
+ * You then obtain this lock, re-check that another thread is still handling
+ * events, then call libusb_wait_for_event().
+ *
+ * You only need to use this lock if you are developing an application
+ * which calls poll() or select() on libusb's file descriptors directly,
+ * <b>and</b> may potentially be handling events from 2 threads simultaenously.
+ * If you stick to libusb's event handling loop functions (e.g.
+ * libusb_handle_events()) then you do not need to be concerned with this
+ * locking.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \see \ref mtasync
+ */
+void API_EXPORTED libusb_lock_event_waiters(libusb_context *ctx)
+{
+ USBI_GET_CONTEXT(ctx);
+ usbi_mutex_lock(&ctx->event_waiters_lock);
+}
+
+/** \ingroup poll
+ * Release the event waiters lock.
+ * \param ctx the context to operate on, or NULL for the default context
+ * \see \ref mtasync
+ */
+void API_EXPORTED libusb_unlock_event_waiters(libusb_context *ctx)
+{
+ USBI_GET_CONTEXT(ctx);
+ usbi_mutex_unlock(&ctx->event_waiters_lock);
+}
+
+/** \ingroup poll
+ * Wait for another thread to signal completion of an event. Must be called
+ * with the event waiters lock held, see libusb_lock_event_waiters().
+ *
+ * This function will block until any of the following conditions are met:
+ * -# The timeout expires
+ * -# A transfer completes
+ * -# A thread releases the event handling lock through libusb_unlock_events()
+ *
+ * Condition 1 is obvious. Condition 2 unblocks your thread <em>after</em>
+ * the callback for the transfer has completed. Condition 3 is important
+ * because it means that the thread that was previously handling events is no
+ * longer doing so, so if any events are to complete, another thread needs to
+ * step up and start event handling.
+ *
+ * This function releases the event waiters lock before putting your thread
+ * to sleep, and reacquires the lock as it is being woken up.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param tv maximum timeout for this blocking function. A NULL value
+ * indicates unlimited timeout.
+ * \returns 0 after a transfer completes or another thread stops event handling
+ * \returns 1 if the timeout expired
+ * \see \ref mtasync
+ */
+int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
+{
+ struct timespec timeout;
+ int r;
+
+ USBI_GET_CONTEXT(ctx);
+ if (tv == NULL) {
+ usbi_cond_wait(&ctx->event_waiters_cond, &ctx->event_waiters_lock);
+ return 0;
+ }
+
+ r = usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &timeout);
+ if (r < 0) {
+ usbi_err(ctx, "failed to read realtime clock, error %d", errno);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ timeout.tv_sec += tv->tv_sec;
+ timeout.tv_nsec += tv->tv_usec * 1000;
+ if (timeout.tv_nsec > 1000000000) {
+ timeout.tv_nsec -= 1000000000;
+ timeout.tv_sec++;
+ }
+
+ r = usbi_cond_timedwait(&ctx->event_waiters_cond,
+ &ctx->event_waiters_lock, &timeout);
+ return (r == ETIMEDOUT);
+}
+
+static void handle_timeout(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ int r;
+
+ itransfer->flags |= USBI_TRANSFER_TIMED_OUT;
+ r = libusb_cancel_transfer(transfer);
+ if (r < 0)
+ usbi_warn(TRANSFER_CTX(transfer),
+ "async cancel failed %d errno=%d", r, errno);
+}
+
+#ifdef USBI_OS_HANDLES_TIMEOUT
+static int handle_timeouts_locked(struct libusb_context *ctx)
+{
+ return 0;
+}
+static int handle_timeouts(struct libusb_context *ctx)
+{
+ return 0;
+}
+#else
+static int handle_timeouts_locked(struct libusb_context *ctx)
+{
+ int r;
+ struct timespec systime_ts;
+ struct timeval systime;
+ struct usbi_transfer *transfer;
+
+ if (list_empty(&ctx->flying_transfers))
+ return 0;
+
+ /* get current time */
+ r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &systime_ts);
+ if (r < 0)
+ return r;
+
+ TIMESPEC_TO_TIMEVAL(&systime, &systime_ts);
+
+ /* iterate through flying transfers list, finding all transfers that
+ * have expired timeouts */
+ list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+ struct timeval *cur_tv = &transfer->timeout;
+
+ /* if we've reached transfers of infinite timeout, we're all done */
+ if (!timerisset(cur_tv))
+ return 0;
+
+ /* ignore timeouts we've already handled */
+ if (transfer->flags & USBI_TRANSFER_TIMED_OUT)
+ continue;
+
+ /* if transfer has non-expired timeout, nothing more to do */
+ if ((cur_tv->tv_sec > systime.tv_sec) ||
+ (cur_tv->tv_sec == systime.tv_sec &&
+ cur_tv->tv_usec > systime.tv_usec))
+ return 0;
+
+ /* otherwise, we've got an expired timeout to handle */
+ handle_timeout(transfer);
+ }
+ return 0;
+}
+
+static int handle_timeouts(struct libusb_context *ctx)
+{
+ int r;
+ USBI_GET_CONTEXT(ctx);
+ usbi_mutex_lock(&ctx->flying_transfers_lock);
+ r = handle_timeouts_locked(ctx);
+ usbi_mutex_unlock(&ctx->flying_transfers_lock);
+ return r;
+}
+#endif
+
+#ifdef USBI_TIMERFD_AVAILABLE
+static int handle_timerfd_trigger(struct libusb_context *ctx)
+{
+ int r;
+
+ r = disarm_timerfd(ctx);
+ if (r < 0)
+ return r;
+
+ usbi_mutex_lock(&ctx->flying_transfers_lock);
+
+ /* process the timeout that just happened */
+ r = handle_timeouts_locked(ctx);
+ if (r < 0)
+ goto out;
+
+ /* arm for next timeout*/
+ r = arm_timerfd_for_next_timeout(ctx);
+
+out:
+ usbi_mutex_unlock(&ctx->flying_transfers_lock);
+ return r;
+}
+#endif
+
+/* do the actual event handling. assumes that no other thread is concurrently
+ * doing the same thing. */
+static int handle_events(struct libusb_context *ctx, struct timeval *tv)
+{
+ int r;
+ struct usbi_pollfd *ipollfd;
+ nfds_t nfds = 0;
+ struct pollfd *fds;
+ int i = -1;
+ int timeout_ms;
+
+ usbi_mutex_lock(&ctx->pollfds_lock);
+ list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd)
+ nfds++;
+
+ /* TODO: malloc when number of fd's changes, not on every poll */
+ fds = malloc(sizeof(*fds) * nfds);
+ if (!fds) {
+ usbi_mutex_unlock(&ctx->pollfds_lock);
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) {
+ struct libusb_pollfd *pollfd = &ipollfd->pollfd;
+ int fd = pollfd->fd;
+ i++;
+ fds[i].fd = fd;
+ fds[i].events = pollfd->events;
+ fds[i].revents = 0;
+ }
+ usbi_mutex_unlock(&ctx->pollfds_lock);
+
+ timeout_ms = (tv->tv_sec * 1000) + (tv->tv_usec / 1000);
+
+ /* round up to next millisecond */
+ if (tv->tv_usec % 1000)
+ timeout_ms++;
+
+ 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) {
+ free(fds);
+ return handle_timeouts(ctx);
+ } else if (r == -1 && errno == EINTR) {
+ free(fds);
+ return LIBUSB_ERROR_INTERRUPTED;
+ } else if (r < 0) {
+ free(fds);
+ usbi_err(ctx, "poll failed %d err=%d\n", r, errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ /* fd[0] is always the ctrl pipe */
+ if (fds[0].revents) {
+ /* another thread wanted to interrupt event handling, and it succeeded!
+ * handle any other events that cropped up at the same time, and
+ * simply return */
+ usbi_dbg("caught a fish on the control pipe");
+
+ if (r == 1) {
+ r = 0;
+ goto handled;
+ } else {
+ /* prevent OS backend from trying to handle events on ctrl pipe */
+ fds[0].revents = 0;
+ r--;
+ }
+ }
+
+#ifdef USBI_TIMERFD_AVAILABLE
+ /* on timerfd configurations, fds[1] is the timerfd */
+ if (usbi_using_timerfd(ctx) && fds[1].revents) {
+ /* timerfd indicates that a timeout has expired */
+ int ret;
+ usbi_dbg("timerfd triggered");
+
+ ret = handle_timerfd_trigger(ctx);
+ if (ret < 0) {
+ /* return error code */
+ r = ret;
+ goto handled;
+ } else if (r == 1) {
+ /* no more active file descriptors, nothing more to do */
+ r = 0;
+ goto handled;
+ } else {
+ /* more events pending...
+ * prevent OS backend from trying to handle events on timerfd */
+ fds[1].revents = 0;
+ r--;
+ }
+ }
+#endif
+
+ r = usbi_backend->handle_events(ctx, fds, nfds, r);
+ if (r)
+ usbi_err(ctx, "backend handle_events failed with error %d", r);
+
+handled:
+ free(fds);
+ return r;
+}
+
+/* returns the smallest of:
+ * 1. timeout of next URB
+ * 2. user-supplied timeout
+ * returns 1 if there is an already-expired timeout, otherwise returns 0
+ * and populates out
+ */
+static int get_next_timeout(libusb_context *ctx, struct timeval *tv,
+ struct timeval *out)
+{
+ struct timeval timeout;
+ int r = libusb_get_next_timeout(ctx, &timeout);
+ if (r) {
+ /* timeout already expired? */
+ if (!timerisset(&timeout))
+ return 1;
+
+ /* choose the smallest of next URB timeout or user specified timeout */
+ if (timercmp(&timeout, tv, <))
+ *out = timeout;
+ else
+ *out = *tv;
+ } else {
+ *out = *tv;
+ }
+ return 0;
+}
+
+/** \ingroup poll
+ * Handle any pending events.
+ *
+ * libusb determines "pending events" by checking if any timeouts have expired
+ * and by checking the set of file descriptors for activity.
+ *
+ * If a zero timeval is passed, this function will handle any already-pending
+ * events and then immediately return in non-blocking style.
+ *
+ * If a non-zero timeval is passed and no events are currently pending, this
+ * function will block waiting for events to handle up until the specified
+ * timeout. If an event arrives or a signal is raised, this function will
+ * return early.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param tv the maximum time to block waiting for events, or zero for
+ * non-blocking mode
+ * \returns 0 on success, or a LIBUSB_ERROR code on failure
+ */
+int API_EXPORTED libusb_handle_events_timeout_check(libusb_context *ctx,
+ struct timeval *tv, int *completed)
+{
+ int r;
+ struct timeval poll_timeout;
+
+ USBI_GET_CONTEXT(ctx);
+ r = get_next_timeout(ctx, tv, &poll_timeout);
+ if (r) {
+ /* timeout already expired */
+ return handle_timeouts(ctx);
+ }
+
+retry:
+ if (libusb_try_lock_events(ctx) == 0) {
+ r = 0;
+ if (completed == NULL || !*completed) {
+ /* we obtained the event lock: do our own event handling */
+ usbi_dbg("doing our own event handling");
+ r = handle_events(ctx, &poll_timeout);
+ }
+ libusb_unlock_events(ctx);
+ return r;
+ }
+
+ /* another thread is doing event handling. wait for pthread events that
+ * notify event completion. */
+ libusb_lock_event_waiters(ctx);
+
+ if (completed == NULL || !*completed) {
+ if (!libusb_event_handler_active(ctx)) {
+ /* we hit a race: whoever was event handling earlier finished in the
+ * time it took us to reach this point. try the cycle again. */
+ libusb_unlock_event_waiters(ctx);
+ usbi_dbg("event handler was active but went away, retrying");
+ goto retry;
+ }
+
+ usbi_dbg("another thread is doing event handling, wait for notification");
+ r = libusb_wait_for_event(ctx, &poll_timeout);
+ }
+ libusb_unlock_event_waiters(ctx);
+
+ if (r < 0)
+ return r;
+ else if (r == 1)
+ return handle_timeouts(ctx);
+ else
+ return 0;
+}
+
+int API_EXPORTED libusb_handle_events_timeout(libusb_context *ctx,
+ struct timeval *tv)
+{
+ return libusb_handle_events_timeout_check(ctx, tv, NULL);
+}
+
+int API_EXPORTED libusb_handle_events_check(libusb_context *ctx,
+ int *completed)
+{
+ struct timeval tv;
+ tv.tv_sec = 60;
+ tv.tv_usec = 0;
+ return libusb_handle_events_timeout_check(ctx, &tv, completed);
+}
+
+/** \ingroup poll
+ * Handle any pending events in blocking mode. There is currently a timeout
+ * hardcoded at 60 seconds but we plan to make it unlimited in future. For
+ * finer control over whether this function is blocking or non-blocking, or
+ * for control over the timeout, use libusb_handle_events_timeout() instead.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \returns 0 on success, or a LIBUSB_ERROR code on failure
+ */
+int API_EXPORTED libusb_handle_events(libusb_context *ctx)
+{
+ struct timeval tv;
+ tv.tv_sec = 60;
+ tv.tv_usec = 0;
+ return libusb_handle_events_timeout_check(ctx, &tv, NULL);
+}
+
+/** \ingroup poll
+ * Handle any pending events by polling file descriptors, without checking if
+ * any other threads are already doing so. Must be called with the event lock
+ * held, see libusb_lock_events().
+ *
+ * This function is designed to be called under the situation where you have
+ * taken the event lock and are calling poll()/select() directly on libusb's
+ * file descriptors (as opposed to using libusb_handle_events() or similar).
+ * You detect events on libusb's descriptors, so you then call this function
+ * with a zero timeout value (while still holding the event lock).
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param tv the maximum time to block waiting for events, or zero for
+ * non-blocking mode
+ * \returns 0 on success, or a LIBUSB_ERROR code on failure
+ * \see \ref mtasync
+ */
+int API_EXPORTED libusb_handle_events_locked(libusb_context *ctx,
+ struct timeval *tv)
+{
+ int r;
+ struct timeval poll_timeout;
+
+ USBI_GET_CONTEXT(ctx);
+ r = get_next_timeout(ctx, tv, &poll_timeout);
+ if (r) {
+ /* timeout already expired */
+ return handle_timeouts(ctx);
+ }
+
+ return handle_events(ctx, &poll_timeout);
+}
+
+/** \ingroup poll
+ * Determines whether your application must apply special timing considerations
+ * when monitoring libusb's file descriptors.
+ *
+ * This function is only useful for applications which retrieve and poll
+ * libusb's file descriptors in their own main loop (\ref pollmain).
+ *
+ * Ordinarily, libusb's event handler needs to be called into at specific
+ * moments in time (in addition to times when there is activity on the file
+ * descriptor set). The usual approach is to use libusb_get_next_timeout()
+ * to learn about when the next timeout occurs, and to adjust your
+ * poll()/select() timeout accordingly so that you can make a call into the
+ * library at that time.
+ *
+ * Some platforms supported by libusb do not come with this baggage - any
+ * events relevant to timing will be represented by activity on the file
+ * descriptor set, and libusb_get_next_timeout() will always return 0.
+ * This function allows you to detect whether you are running on such a
+ * platform.
+ *
+ * Since v1.0.5.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \returns 0 if you must call into libusb at times determined by
+ * libusb_get_next_timeout(), or 1 if all timeout events are handled internally
+ * or through regular activity on the file descriptors.
+ * \see \ref pollmain "Polling libusb file descriptors for event handling"
+ */
+int API_EXPORTED libusb_pollfds_handle_timeouts(libusb_context *ctx)
+{
+#if defined(USBI_OS_HANDLES_TIMEOUT)
+ return 1;
+#elif defined(USBI_TIMERFD_AVAILABLE)
+ USBI_GET_CONTEXT(ctx);
+ return usbi_using_timerfd(ctx);
+#else
+ return 0;
+#endif
+}
+
+/** \ingroup poll
+ * Determine the next internal timeout that libusb needs to handle. You only
+ * need to use this function if you are calling poll() or select() or similar
+ * on libusb's file descriptors yourself - you do not need to use it if you
+ * are calling libusb_handle_events() or a variant directly.
+ *
+ * You should call this function in your main loop in order to determine how
+ * long to wait for select() or poll() to return results. libusb needs to be
+ * called into at this timeout, so you should use it as an upper bound on
+ * your select() or poll() call.
+ *
+ * When the timeout has expired, call into libusb_handle_events_timeout()
+ * (perhaps in non-blocking mode) so that libusb can handle the timeout.
+ *
+ * This function may return 1 (success) and an all-zero timeval. If this is
+ * the case, it indicates that libusb has a timeout that has already expired
+ * so you should call libusb_handle_events_timeout() or similar immediately.
+ * A return code of 0 indicates that there are no pending timeouts.
+ *
+ * On some platforms, this function will always returns 0 (no pending
+ * timeouts). See \ref polltime.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param tv output location for a relative time against the current
+ * clock in which libusb must be called into in order to process timeout events
+ * \returns 0 if there are no pending timeouts, 1 if a timeout was returned,
+ * or LIBUSB_ERROR_OTHER on failure
+ */
+int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
+ struct timeval *tv)
+{
+#ifndef USBI_OS_HANDLES_TIMEOUT
+ struct usbi_transfer *transfer;
+ struct timespec cur_ts;
+ struct timeval cur_tv;
+ struct timeval *next_timeout;
+ int r;
+ int found = 0;
+
+ USBI_GET_CONTEXT(ctx);
+ if (usbi_using_timerfd(ctx))
+ return 0;
+
+ usbi_mutex_lock(&ctx->flying_transfers_lock);
+ if (list_empty(&ctx->flying_transfers)) {
+ usbi_mutex_unlock(&ctx->flying_transfers_lock);
+ usbi_dbg("no URBs, no timeout!");
+ return 0;
+ }
+
+ /* find next transfer which hasn't already been processed as timed out */
+ list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+ if (!(transfer->flags & USBI_TRANSFER_TIMED_OUT)) {
+ found = 1;
+ break;
+ }
+ }
+ usbi_mutex_unlock(&ctx->flying_transfers_lock);
+
+ if (!found) {
+ usbi_dbg("all URBs have already been processed for timeouts");
+ return 0;
+ }
+
+ next_timeout = &transfer->timeout;
+
+ /* no timeout for next transfer */
+ if (!timerisset(next_timeout)) {
+ usbi_dbg("no URBs with timeouts, no timeout!");
+ return 0;
+ }
+
+ 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 LIBUSB_ERROR_OTHER;
+ }
+ TIMESPEC_TO_TIMEVAL(&cur_tv, &cur_ts);
+
+ if (!timercmp(&cur_tv, next_timeout, <)) {
+ usbi_dbg("first timeout already expired");
+ timerclear(tv);
+ } else {
+ timersub(next_timeout, &cur_tv, tv);
+ usbi_dbg("next timeout in %d.%06ds", tv->tv_sec, tv->tv_usec);
+ }
+
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+/** \ingroup poll
+ * Register notification functions for file descriptor additions/removals.
+ * These functions will be invoked for every new or removed file descriptor
+ * that libusb uses as an event source.
+ *
+ * To remove notifiers, pass NULL values for the function pointers.
+ *
+ * Note that file descriptors may have been added even before you register
+ * these notifiers (e.g. at libusb_init() time).
+ *
+ * Additionally, note that the removal notifier may be called during
+ * libusb_exit() (e.g. when it is closing file descriptors that were opened
+ * and added to the poll set at libusb_init() time). If you don't want this,
+ * remove the notifiers immediately before calling libusb_exit().
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param added_cb pointer to function for addition notifications
+ * \param removed_cb pointer to function for removal notifications
+ * \param user_data User data to be passed back to callbacks (useful for
+ * passing context information)
+ */
+void API_EXPORTED libusb_set_pollfd_notifiers(libusb_context *ctx,
+ libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
+ void *user_data)
+{
+ USBI_GET_CONTEXT(ctx);
+ ctx->fd_added_cb = added_cb;
+ ctx->fd_removed_cb = removed_cb;
+ ctx->fd_cb_user_data = user_data;
+}
+
+/* Add a file descriptor to the list of file descriptors to be monitored.
+ * events should be specified as a bitmask of events passed to poll(), e.g.
+ * POLLIN and/or POLLOUT. */
+int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events)
+{
+ struct usbi_pollfd *ipollfd = malloc(sizeof(*ipollfd));
+ if (!ipollfd)
+ return LIBUSB_ERROR_NO_MEM;
+
+ usbi_dbg("add fd %d events %d", fd, events);
+ ipollfd->pollfd.fd = fd;
+ ipollfd->pollfd.events = events;
+ usbi_mutex_lock(&ctx->pollfds_lock);
+ list_add_tail(&ipollfd->list, &ctx->pollfds);
+ usbi_mutex_unlock(&ctx->pollfds_lock);
+
+ if (ctx->fd_added_cb)
+ ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data);
+ return 0;
+}
+
+/* Remove a file descriptor from the list of file descriptors to be polled. */
+void usbi_remove_pollfd(struct libusb_context *ctx, int fd)
+{
+ struct usbi_pollfd *ipollfd;
+ int found = 0;
+
+ usbi_dbg("remove fd %d", fd);
+ usbi_mutex_lock(&ctx->pollfds_lock);
+ list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd)
+ if (ipollfd->pollfd.fd == fd) {
+ found = 1;
+ break;
+ }
+
+ if (!found) {
+ usbi_dbg("couldn't find fd %d to remove", fd);
+ usbi_mutex_unlock(&ctx->pollfds_lock);
+ return;
+ }
+
+ list_del(&ipollfd->list);
+ usbi_mutex_unlock(&ctx->pollfds_lock);
+ free(ipollfd);
+ if (ctx->fd_removed_cb)
+ ctx->fd_removed_cb(fd, ctx->fd_cb_user_data);
+}
+
+/** \ingroup poll
+ * Retrieve a list of file descriptors that should be polled by your main loop
+ * as libusb event sources.
+ *
+ * The returned list is NULL-terminated and should be freed with free() when
+ * done. The actual list contents must not be touched.
+ *
+ * As file descriptors are a Unix-specific concept, this function is not
+ * available on Windows and will always return NULL.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \returns a NULL-terminated list of libusb_pollfd structures
+ * \returns NULL on error
+ * \returns NULL on platforms where the functionality is not available
+ */
+DEFAULT_VISIBILITY
+const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds(
+ libusb_context *ctx)
+{
+#ifndef OS_WINDOWS
+ struct libusb_pollfd **ret = NULL;
+ struct usbi_pollfd *ipollfd;
+ size_t i = 0;
+ size_t cnt = 0;
+ USBI_GET_CONTEXT(ctx);
+
+ usbi_mutex_lock(&ctx->pollfds_lock);
+ list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd)
+ cnt++;
+
+ ret = calloc(cnt + 1, sizeof(struct libusb_pollfd *));
+ if (!ret)
+ goto out;
+
+ list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd)
+ ret[i++] = (struct libusb_pollfd *) ipollfd;
+ ret[cnt] = NULL;
+
+out:
+ usbi_mutex_unlock(&ctx->pollfds_lock);
+ return (const struct libusb_pollfd **) ret;
+#else
+ return NULL;
+#endif
+}
+
+/* Backends call this from handle_events to report disconnection of a device.
+ * The transfers get cancelled appropriately.
+ */
+void usbi_handle_disconnect(struct libusb_device_handle *handle)
+{
+ struct usbi_transfer *cur;
+ struct usbi_transfer *to_cancel;
+
+ usbi_dbg("device %d.%d",
+ handle->dev->bus_number, handle->dev->device_address);
+
+ /* terminate all pending transfers with the LIBUSB_TRANSFER_NO_DEVICE
+ * status code.
+ *
+ * this is a bit tricky because:
+ * 1. we can't do transfer completion while holding flying_transfers_lock
+ * 2. the transfers list can change underneath us - if we were to build a
+ * list of transfers to complete (while holding look), the situation
+ * might be different by the time we come to free them
+ *
+ * so we resort to a loop-based approach as below
+ * FIXME: is this still potentially racy?
+ */
+
+ while (1) {
+ usbi_mutex_lock(&HANDLE_CTX(handle)->flying_transfers_lock);
+ to_cancel = NULL;
+ list_for_each_entry(cur, &HANDLE_CTX(handle)->flying_transfers, list, struct usbi_transfer)
+ if (__USBI_TRANSFER_TO_LIBUSB_TRANSFER(cur)->dev_handle == handle) {
+ to_cancel = cur;
+ break;
+ }
+ usbi_mutex_unlock(&HANDLE_CTX(handle)->flying_transfers_lock);
+
+ if (!to_cancel)
+ break;
+
+ usbi_backend->clear_transfer_priv(to_cancel);
+ usbi_handle_transfer_completion(to_cancel, LIBUSB_TRANSFER_NO_DEVICE);
+ }
+
+}
diff --git a/libusb-1.0/libusb/libusb-1.0.def b/libusb-1.0/libusb/libusb-1.0.def
new file mode 100644
index 0000000..fe609e0
--- /dev/null
+++ b/libusb-1.0/libusb/libusb-1.0.def
@@ -0,0 +1,572 @@
+LIBRARY
+EXPORTS
+ libusb_get_device_list
+ libusb_free_device_list
+ libusb_get_bus_number
+ libusb_get_device_address
+ libusb_get_max_packet_size
+ libusb_get_max_iso_packet_size
+ libusb_unref_device
+ libusb_open
+ libusb_close
+ libusb_get_configuration
+ libusb_set_configuration
+ libusb_claim_interface
+ libusb_release_interface
+ libusb_set_interface_alt_setting
+ libusb_clear_halt
+ libusb_reset_device
+ libusb_kernel_driver_active
+ libusb_detach_kernel_driver
+ libusb_attach_kernel_driver
+ libusb_set_debug
+ libusb_init
+ libusb_exit
+ libusb_get_device_descriptor
+ libusb_get_active_config_descriptor
+ libusb_get_config_descriptor
+ libusb_get_config_descriptor_by_value
+ libusb_free_config_descriptor
+ libusb_get_string_descriptor_ascii
+ libusb_free_transfer
+ libusb_submit_transfer
+ libusb_cancel_transfer
+ libusb_try_lock_events
+ libusb_lock_events
+ libusb_unlock_events
+ libusb_event_handling_ok
+ libusb_event_handler_active
+ libusb_lock_event_waiters
+ libusb_unlock_event_waiters
+ libusb_wait_for_event
+ libusb_handle_events_timeout_check
+ libusb_handle_events_timeout
+ libusb_handle_events_check
+ libusb_handle_events
+ libusb_handle_events_locked
+ libusb_pollfds_handle_timeouts
+ libusb_get_next_timeout
+ libusb_set_pollfd_notifiers
+ libusb_control_transfer
+ libusb_bulk_transfer
+ libusb_interrupt_transfer
+ libusb_ref_device
+ libusb_open_device_with_vid_pid
+ libusb_get_device
+ libusb_strerror
+ libusb_getversion
+ libusb_alloc_transfer
+ libusb_get_pollfds
+ libusb_get_device_list@0 = libusb_get_device_list
+ libusb_free_device_list@0 = libusb_free_device_list
+ libusb_get_bus_number@0 = libusb_get_bus_number
+ libusb_get_device_address@0 = libusb_get_device_address
+ libusb_get_max_packet_size@0 = libusb_get_max_packet_size
+ libusb_get_max_iso_packet_size@0 = libusb_get_max_iso_packet_size
+ libusb_unref_device@0 = libusb_unref_device
+ libusb_open@0 = libusb_open
+ libusb_close@0 = libusb_close
+ libusb_get_configuration@0 = libusb_get_configuration
+ libusb_set_configuration@0 = libusb_set_configuration
+ libusb_claim_interface@0 = libusb_claim_interface
+ libusb_release_interface@0 = libusb_release_interface
+ libusb_set_interface_alt_setting@0 = libusb_set_interface_alt_setting
+ libusb_clear_halt@0 = libusb_clear_halt
+ libusb_reset_device@0 = libusb_reset_device
+ libusb_kernel_driver_active@0 = libusb_kernel_driver_active
+ libusb_detach_kernel_driver@0 = libusb_detach_kernel_driver
+ libusb_attach_kernel_driver@0 = libusb_attach_kernel_driver
+ libusb_set_debug@0 = libusb_set_debug
+ libusb_init@0 = libusb_init
+ libusb_exit@0 = libusb_exit
+ libusb_get_device_descriptor@0 = libusb_get_device_descriptor
+ libusb_get_active_config_descriptor@0 = libusb_get_active_config_descriptor
+ libusb_get_config_descriptor@0 = libusb_get_config_descriptor
+ libusb_get_config_descriptor_by_value@0 = libusb_get_config_descriptor_by_value
+ libusb_free_config_descriptor@0 = libusb_free_config_descriptor
+ libusb_get_string_descriptor_ascii@0 = libusb_get_string_descriptor_ascii
+ libusb_free_transfer@0 = libusb_free_transfer
+ libusb_submit_transfer@0 = libusb_submit_transfer
+ libusb_cancel_transfer@0 = libusb_cancel_transfer
+ libusb_try_lock_events@0 = libusb_try_lock_events
+ libusb_lock_events@0 = libusb_lock_events
+ libusb_unlock_events@0 = libusb_unlock_events
+ libusb_event_handling_ok@0 = libusb_event_handling_ok
+ libusb_event_handler_active@0 = libusb_event_handler_active
+ libusb_lock_event_waiters@0 = libusb_lock_event_waiters
+ libusb_unlock_event_waiters@0 = libusb_unlock_event_waiters
+ libusb_wait_for_event@0 = libusb_wait_for_event
+ libusb_handle_events_timeout_check@0 = libusb_handle_events_timeout_check
+ libusb_handle_events_timeout@0 = libusb_handle_events_timeout
+ libusb_handle_events_check@0 = libusb_handle_events_check
+ libusb_handle_events@0 = libusb_handle_events
+ libusb_handle_events_locked@0 = libusb_handle_events_locked
+ libusb_pollfds_handle_timeouts@0 = libusb_pollfds_handle_timeouts
+ libusb_get_next_timeout@0 = libusb_get_next_timeout
+ libusb_set_pollfd_notifiers@0 = libusb_set_pollfd_notifiers
+ libusb_control_transfer@0 = libusb_control_transfer
+ libusb_bulk_transfer@0 = libusb_bulk_transfer
+ libusb_interrupt_transfer@0 = libusb_interrupt_transfer
+ libusb_ref_device@0 = libusb_ref_device
+ libusb_open_device_with_vid_pid@0 = libusb_open_device_with_vid_pid
+ libusb_get_device@0 = libusb_get_device
+ libusb_strerror@0 = libusb_strerror
+ libusb_getversion@0 = libusb_getversion
+ libusb_alloc_transfer@0 = libusb_alloc_transfer
+ libusb_get_pollfds@0 = libusb_get_pollfds
+ libusb_get_device_list@4 = libusb_get_device_list
+ libusb_free_device_list@4 = libusb_free_device_list
+ libusb_get_bus_number@4 = libusb_get_bus_number
+ libusb_get_device_address@4 = libusb_get_device_address
+ libusb_get_max_packet_size@4 = libusb_get_max_packet_size
+ libusb_get_max_iso_packet_size@4 = libusb_get_max_iso_packet_size
+ libusb_unref_device@4 = libusb_unref_device
+ libusb_open@4 = libusb_open
+ libusb_close@4 = libusb_close
+ libusb_get_configuration@4 = libusb_get_configuration
+ libusb_set_configuration@4 = libusb_set_configuration
+ libusb_claim_interface@4 = libusb_claim_interface
+ libusb_release_interface@4 = libusb_release_interface
+ libusb_set_interface_alt_setting@4 = libusb_set_interface_alt_setting
+ libusb_clear_halt@4 = libusb_clear_halt
+ libusb_reset_device@4 = libusb_reset_device
+ libusb_kernel_driver_active@4 = libusb_kernel_driver_active
+ libusb_detach_kernel_driver@4 = libusb_detach_kernel_driver
+ libusb_attach_kernel_driver@4 = libusb_attach_kernel_driver
+ libusb_set_debug@4 = libusb_set_debug
+ libusb_init@4 = libusb_init
+ libusb_exit@4 = libusb_exit
+ libusb_get_device_descriptor@4 = libusb_get_device_descriptor
+ libusb_get_active_config_descriptor@4 = libusb_get_active_config_descriptor
+ libusb_get_config_descriptor@4 = libusb_get_config_descriptor
+ libusb_get_config_descriptor_by_value@4 = libusb_get_config_descriptor_by_value
+ libusb_free_config_descriptor@4 = libusb_free_config_descriptor
+ libusb_get_string_descriptor_ascii@4 = libusb_get_string_descriptor_ascii
+ libusb_free_transfer@4 = libusb_free_transfer
+ libusb_submit_transfer@4 = libusb_submit_transfer
+ libusb_cancel_transfer@4 = libusb_cancel_transfer
+ libusb_try_lock_events@4 = libusb_try_lock_events
+ libusb_lock_events@4 = libusb_lock_events
+ libusb_unlock_events@4 = libusb_unlock_events
+ libusb_event_handling_ok@4 = libusb_event_handling_ok
+ libusb_event_handler_active@4 = libusb_event_handler_active
+ libusb_lock_event_waiters@4 = libusb_lock_event_waiters
+ libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters
+ libusb_wait_for_event@4 = libusb_wait_for_event
+ libusb_handle_events_timeout_check@4 = libusb_handle_events_timeout_check
+ libusb_handle_events_timeout@4 = libusb_handle_events_timeout
+ libusb_handle_events_check@4 = libusb_handle_events_check
+ libusb_handle_events@4 = libusb_handle_events
+ libusb_handle_events_locked@4 = libusb_handle_events_locked
+ libusb_pollfds_handle_timeouts@4 = libusb_pollfds_handle_timeouts
+ libusb_get_next_timeout@4 = libusb_get_next_timeout
+ libusb_set_pollfd_notifiers@4 = libusb_set_pollfd_notifiers
+ libusb_control_transfer@4 = libusb_control_transfer
+ libusb_bulk_transfer@4 = libusb_bulk_transfer
+ libusb_interrupt_transfer@4 = libusb_interrupt_transfer
+ libusb_ref_device@4 = libusb_ref_device
+ libusb_open_device_with_vid_pid@4 = libusb_open_device_with_vid_pid
+ libusb_get_device@4 = libusb_get_device
+ libusb_strerror@4 = libusb_strerror
+ libusb_getversion@4 = libusb_getversion
+ libusb_alloc_transfer@4 = libusb_alloc_transfer
+ libusb_get_pollfds@4 = libusb_get_pollfds
+ libusb_get_device_list@8 = libusb_get_device_list
+ libusb_free_device_list@8 = libusb_free_device_list
+ libusb_get_bus_number@8 = libusb_get_bus_number
+ libusb_get_device_address@8 = libusb_get_device_address
+ libusb_get_max_packet_size@8 = libusb_get_max_packet_size
+ libusb_get_max_iso_packet_size@8 = libusb_get_max_iso_packet_size
+ libusb_unref_device@8 = libusb_unref_device
+ libusb_open@8 = libusb_open
+ libusb_close@8 = libusb_close
+ libusb_get_configuration@8 = libusb_get_configuration
+ libusb_set_configuration@8 = libusb_set_configuration
+ libusb_claim_interface@8 = libusb_claim_interface
+ libusb_release_interface@8 = libusb_release_interface
+ libusb_set_interface_alt_setting@8 = libusb_set_interface_alt_setting
+ libusb_clear_halt@8 = libusb_clear_halt
+ libusb_reset_device@8 = libusb_reset_device
+ libusb_kernel_driver_active@8 = libusb_kernel_driver_active
+ libusb_detach_kernel_driver@8 = libusb_detach_kernel_driver
+ libusb_attach_kernel_driver@8 = libusb_attach_kernel_driver
+ libusb_set_debug@8 = libusb_set_debug
+ libusb_init@8 = libusb_init
+ libusb_exit@8 = libusb_exit
+ libusb_get_device_descriptor@8 = libusb_get_device_descriptor
+ libusb_get_active_config_descriptor@8 = libusb_get_active_config_descriptor
+ libusb_get_config_descriptor@8 = libusb_get_config_descriptor
+ libusb_get_config_descriptor_by_value@8 = libusb_get_config_descriptor_by_value
+ libusb_free_config_descriptor@8 = libusb_free_config_descriptor
+ libusb_get_string_descriptor_ascii@8 = libusb_get_string_descriptor_ascii
+ libusb_free_transfer@8 = libusb_free_transfer
+ libusb_submit_transfer@8 = libusb_submit_transfer
+ libusb_cancel_transfer@8 = libusb_cancel_transfer
+ libusb_try_lock_events@8 = libusb_try_lock_events
+ libusb_lock_events@8 = libusb_lock_events
+ libusb_unlock_events@8 = libusb_unlock_events
+ libusb_event_handling_ok@8 = libusb_event_handling_ok
+ libusb_event_handler_active@8 = libusb_event_handler_active
+ libusb_lock_event_waiters@8 = libusb_lock_event_waiters
+ libusb_unlock_event_waiters@8 = libusb_unlock_event_waiters
+ libusb_wait_for_event@8 = libusb_wait_for_event
+ libusb_handle_events_timeout_check@8 = libusb_handle_events_timeout_check
+ libusb_handle_events_timeout@8 = libusb_handle_events_timeout
+ libusb_handle_events_check@8 = libusb_handle_events_check
+ libusb_handle_events@8 = libusb_handle_events
+ libusb_handle_events_locked@8 = libusb_handle_events_locked
+ libusb_pollfds_handle_timeouts@8 = libusb_pollfds_handle_timeouts
+ libusb_get_next_timeout@8 = libusb_get_next_timeout
+ libusb_set_pollfd_notifiers@8 = libusb_set_pollfd_notifiers
+ libusb_control_transfer@8 = libusb_control_transfer
+ libusb_bulk_transfer@8 = libusb_bulk_transfer
+ libusb_interrupt_transfer@8 = libusb_interrupt_transfer
+ libusb_ref_device@8 = libusb_ref_device
+ libusb_open_device_with_vid_pid@8 = libusb_open_device_with_vid_pid
+ libusb_get_device@8 = libusb_get_device
+ libusb_strerror@8 = libusb_strerror
+ libusb_getversion@8 = libusb_getversion
+ libusb_alloc_transfer@8 = libusb_alloc_transfer
+ libusb_get_pollfds@8 = libusb_get_pollfds
+ libusb_get_device_list@12 = libusb_get_device_list
+ libusb_free_device_list@12 = libusb_free_device_list
+ libusb_get_bus_number@12 = libusb_get_bus_number
+ libusb_get_device_address@12 = libusb_get_device_address
+ libusb_get_max_packet_size@12 = libusb_get_max_packet_size
+ libusb_get_max_iso_packet_size@12 = libusb_get_max_iso_packet_size
+ libusb_unref_device@12 = libusb_unref_device
+ libusb_open@12 = libusb_open
+ libusb_close@12 = libusb_close
+ libusb_get_configuration@12 = libusb_get_configuration
+ libusb_set_configuration@12 = libusb_set_configuration
+ libusb_claim_interface@12 = libusb_claim_interface
+ libusb_release_interface@12 = libusb_release_interface
+ libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting
+ libusb_clear_halt@12 = libusb_clear_halt
+ libusb_reset_device@12 = libusb_reset_device
+ libusb_kernel_driver_active@12 = libusb_kernel_driver_active
+ libusb_detach_kernel_driver@12 = libusb_detach_kernel_driver
+ libusb_attach_kernel_driver@12 = libusb_attach_kernel_driver
+ libusb_set_debug@12 = libusb_set_debug
+ libusb_init@12 = libusb_init
+ libusb_exit@12 = libusb_exit
+ libusb_get_device_descriptor@12 = libusb_get_device_descriptor
+ libusb_get_active_config_descriptor@12 = libusb_get_active_config_descriptor
+ libusb_get_config_descriptor@12 = libusb_get_config_descriptor
+ libusb_get_config_descriptor_by_value@12 = libusb_get_config_descriptor_by_value
+ libusb_free_config_descriptor@12 = libusb_free_config_descriptor
+ libusb_get_string_descriptor_ascii@12 = libusb_get_string_descriptor_ascii
+ libusb_free_transfer@12 = libusb_free_transfer
+ libusb_submit_transfer@12 = libusb_submit_transfer
+ libusb_cancel_transfer@12 = libusb_cancel_transfer
+ libusb_try_lock_events@12 = libusb_try_lock_events
+ libusb_lock_events@12 = libusb_lock_events
+ libusb_unlock_events@12 = libusb_unlock_events
+ libusb_event_handling_ok@12 = libusb_event_handling_ok
+ libusb_event_handler_active@12 = libusb_event_handler_active
+ libusb_lock_event_waiters@12 = libusb_lock_event_waiters
+ libusb_unlock_event_waiters@12 = libusb_unlock_event_waiters
+ libusb_wait_for_event@12 = libusb_wait_for_event
+ libusb_handle_events_timeout_check@12 = libusb_handle_events_timeout_check
+ libusb_handle_events_timeout@12 = libusb_handle_events_timeout
+ libusb_handle_events_check@12 = libusb_handle_events_check
+ libusb_handle_events@12 = libusb_handle_events
+ libusb_handle_events_locked@12 = libusb_handle_events_locked
+ libusb_pollfds_handle_timeouts@12 = libusb_pollfds_handle_timeouts
+ libusb_get_next_timeout@12 = libusb_get_next_timeout
+ libusb_set_pollfd_notifiers@12 = libusb_set_pollfd_notifiers
+ libusb_control_transfer@12 = libusb_control_transfer
+ libusb_bulk_transfer@12 = libusb_bulk_transfer
+ libusb_interrupt_transfer@12 = libusb_interrupt_transfer
+ libusb_ref_device@12 = libusb_ref_device
+ libusb_open_device_with_vid_pid@12 = libusb_open_device_with_vid_pid
+ libusb_get_device@12 = libusb_get_device
+ libusb_strerror@12 = libusb_strerror
+ libusb_getversion@12 = libusb_getversion
+ libusb_alloc_transfer@12 = libusb_alloc_transfer
+ libusb_get_pollfds@12 = libusb_get_pollfds
+ libusb_get_device_list@16 = libusb_get_device_list
+ libusb_free_device_list@16 = libusb_free_device_list
+ libusb_get_bus_number@16 = libusb_get_bus_number
+ libusb_get_device_address@16 = libusb_get_device_address
+ libusb_get_max_packet_size@16 = libusb_get_max_packet_size
+ libusb_get_max_iso_packet_size@16 = libusb_get_max_iso_packet_size
+ libusb_unref_device@16 = libusb_unref_device
+ libusb_open@16 = libusb_open
+ libusb_close@16 = libusb_close
+ libusb_get_configuration@16 = libusb_get_configuration
+ libusb_set_configuration@16 = libusb_set_configuration
+ libusb_claim_interface@16 = libusb_claim_interface
+ libusb_release_interface@16 = libusb_release_interface
+ libusb_set_interface_alt_setting@16 = libusb_set_interface_alt_setting
+ libusb_clear_halt@16 = libusb_clear_halt
+ libusb_reset_device@16 = libusb_reset_device
+ libusb_kernel_driver_active@16 = libusb_kernel_driver_active
+ libusb_detach_kernel_driver@16 = libusb_detach_kernel_driver
+ libusb_attach_kernel_driver@16 = libusb_attach_kernel_driver
+ libusb_set_debug@16 = libusb_set_debug
+ libusb_init@16 = libusb_init
+ libusb_exit@16 = libusb_exit
+ libusb_get_device_descriptor@16 = libusb_get_device_descriptor
+ libusb_get_active_config_descriptor@16 = libusb_get_active_config_descriptor
+ libusb_get_config_descriptor@16 = libusb_get_config_descriptor
+ libusb_get_config_descriptor_by_value@16 = libusb_get_config_descriptor_by_value
+ libusb_free_config_descriptor@16 = libusb_free_config_descriptor
+ libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii
+ libusb_free_transfer@16 = libusb_free_transfer
+ libusb_submit_transfer@16 = libusb_submit_transfer
+ libusb_cancel_transfer@16 = libusb_cancel_transfer
+ libusb_try_lock_events@16 = libusb_try_lock_events
+ libusb_lock_events@16 = libusb_lock_events
+ libusb_unlock_events@16 = libusb_unlock_events
+ libusb_event_handling_ok@16 = libusb_event_handling_ok
+ libusb_event_handler_active@16 = libusb_event_handler_active
+ libusb_lock_event_waiters@16 = libusb_lock_event_waiters
+ libusb_unlock_event_waiters@16 = libusb_unlock_event_waiters
+ libusb_wait_for_event@16 = libusb_wait_for_event
+ libusb_handle_events_timeout_check@16 = libusb_handle_events_timeout_check
+ libusb_handle_events_timeout@16 = libusb_handle_events_timeout
+ libusb_handle_events_check@16 = libusb_handle_events_check
+ libusb_handle_events@16 = libusb_handle_events
+ libusb_handle_events_locked@16 = libusb_handle_events_locked
+ libusb_pollfds_handle_timeouts@16 = libusb_pollfds_handle_timeouts
+ libusb_get_next_timeout@16 = libusb_get_next_timeout
+ libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers
+ libusb_control_transfer@16 = libusb_control_transfer
+ libusb_bulk_transfer@16 = libusb_bulk_transfer
+ libusb_interrupt_transfer@16 = libusb_interrupt_transfer
+ libusb_ref_device@16 = libusb_ref_device
+ libusb_open_device_with_vid_pid@16 = libusb_open_device_with_vid_pid
+ libusb_get_device@16 = libusb_get_device
+ libusb_strerror@16 = libusb_strerror
+ libusb_getversion@16 = libusb_getversion
+ libusb_alloc_transfer@16 = libusb_alloc_transfer
+ libusb_get_pollfds@16 = libusb_get_pollfds
+ libusb_get_device_list@20 = libusb_get_device_list
+ libusb_free_device_list@20 = libusb_free_device_list
+ libusb_get_bus_number@20 = libusb_get_bus_number
+ libusb_get_device_address@20 = libusb_get_device_address
+ libusb_get_max_packet_size@20 = libusb_get_max_packet_size
+ libusb_get_max_iso_packet_size@20 = libusb_get_max_iso_packet_size
+ libusb_unref_device@20 = libusb_unref_device
+ libusb_open@20 = libusb_open
+ libusb_close@20 = libusb_close
+ libusb_get_configuration@20 = libusb_get_configuration
+ libusb_set_configuration@20 = libusb_set_configuration
+ libusb_claim_interface@20 = libusb_claim_interface
+ libusb_release_interface@20 = libusb_release_interface
+ libusb_set_interface_alt_setting@20 = libusb_set_interface_alt_setting
+ libusb_clear_halt@20 = libusb_clear_halt
+ libusb_reset_device@20 = libusb_reset_device
+ libusb_kernel_driver_active@20 = libusb_kernel_driver_active
+ libusb_detach_kernel_driver@20 = libusb_detach_kernel_driver
+ libusb_attach_kernel_driver@20 = libusb_attach_kernel_driver
+ libusb_set_debug@20 = libusb_set_debug
+ libusb_init@20 = libusb_init
+ libusb_exit@20 = libusb_exit
+ libusb_get_device_descriptor@20 = libusb_get_device_descriptor
+ libusb_get_active_config_descriptor@20 = libusb_get_active_config_descriptor
+ libusb_get_config_descriptor@20 = libusb_get_config_descriptor
+ libusb_get_config_descriptor_by_value@20 = libusb_get_config_descriptor_by_value
+ libusb_free_config_descriptor@20 = libusb_free_config_descriptor
+ libusb_get_string_descriptor_ascii@20 = libusb_get_string_descriptor_ascii
+ libusb_free_transfer@20 = libusb_free_transfer
+ libusb_submit_transfer@20 = libusb_submit_transfer
+ libusb_cancel_transfer@20 = libusb_cancel_transfer
+ libusb_try_lock_events@20 = libusb_try_lock_events
+ libusb_lock_events@20 = libusb_lock_events
+ libusb_unlock_events@20 = libusb_unlock_events
+ libusb_event_handling_ok@20 = libusb_event_handling_ok
+ libusb_event_handler_active@20 = libusb_event_handler_active
+ libusb_lock_event_waiters@20 = libusb_lock_event_waiters
+ libusb_unlock_event_waiters@20 = libusb_unlock_event_waiters
+ libusb_wait_for_event@20 = libusb_wait_for_event
+ libusb_handle_events_timeout_check@20 = libusb_handle_events_timeout_check
+ libusb_handle_events_timeout@20 = libusb_handle_events_timeout
+ libusb_handle_events_check@20 = libusb_handle_events_check
+ libusb_handle_events@20 = libusb_handle_events
+ libusb_handle_events_locked@20 = libusb_handle_events_locked
+ libusb_pollfds_handle_timeouts@20 = libusb_pollfds_handle_timeouts
+ libusb_get_next_timeout@20 = libusb_get_next_timeout
+ libusb_set_pollfd_notifiers@20 = libusb_set_pollfd_notifiers
+ libusb_control_transfer@20 = libusb_control_transfer
+ libusb_bulk_transfer@20 = libusb_bulk_transfer
+ libusb_interrupt_transfer@20 = libusb_interrupt_transfer
+ libusb_ref_device@20 = libusb_ref_device
+ libusb_open_device_with_vid_pid@20 = libusb_open_device_with_vid_pid
+ libusb_get_device@20 = libusb_get_device
+ libusb_strerror@20 = libusb_strerror
+ libusb_getversion@20 = libusb_getversion
+ libusb_alloc_transfer@20 = libusb_alloc_transfer
+ libusb_get_pollfds@20 = libusb_get_pollfds
+ libusb_get_device_list@24 = libusb_get_device_list
+ libusb_free_device_list@24 = libusb_free_device_list
+ libusb_get_bus_number@24 = libusb_get_bus_number
+ libusb_get_device_address@24 = libusb_get_device_address
+ libusb_get_max_packet_size@24 = libusb_get_max_packet_size
+ libusb_get_max_iso_packet_size@24 = libusb_get_max_iso_packet_size
+ libusb_unref_device@24 = libusb_unref_device
+ libusb_open@24 = libusb_open
+ libusb_close@24 = libusb_close
+ libusb_get_configuration@24 = libusb_get_configuration
+ libusb_set_configuration@24 = libusb_set_configuration
+ libusb_claim_interface@24 = libusb_claim_interface
+ libusb_release_interface@24 = libusb_release_interface
+ libusb_set_interface_alt_setting@24 = libusb_set_interface_alt_setting
+ libusb_clear_halt@24 = libusb_clear_halt
+ libusb_reset_device@24 = libusb_reset_device
+ libusb_kernel_driver_active@24 = libusb_kernel_driver_active
+ libusb_detach_kernel_driver@24 = libusb_detach_kernel_driver
+ libusb_attach_kernel_driver@24 = libusb_attach_kernel_driver
+ libusb_set_debug@24 = libusb_set_debug
+ libusb_init@24 = libusb_init
+ libusb_exit@24 = libusb_exit
+ libusb_get_device_descriptor@24 = libusb_get_device_descriptor
+ libusb_get_active_config_descriptor@24 = libusb_get_active_config_descriptor
+ libusb_get_config_descriptor@24 = libusb_get_config_descriptor
+ libusb_get_config_descriptor_by_value@24 = libusb_get_config_descriptor_by_value
+ libusb_free_config_descriptor@24 = libusb_free_config_descriptor
+ libusb_get_string_descriptor_ascii@24 = libusb_get_string_descriptor_ascii
+ libusb_free_transfer@24 = libusb_free_transfer
+ libusb_submit_transfer@24 = libusb_submit_transfer
+ libusb_cancel_transfer@24 = libusb_cancel_transfer
+ libusb_try_lock_events@24 = libusb_try_lock_events
+ libusb_lock_events@24 = libusb_lock_events
+ libusb_unlock_events@24 = libusb_unlock_events
+ libusb_event_handling_ok@24 = libusb_event_handling_ok
+ libusb_event_handler_active@24 = libusb_event_handler_active
+ libusb_lock_event_waiters@24 = libusb_lock_event_waiters
+ libusb_unlock_event_waiters@24 = libusb_unlock_event_waiters
+ libusb_wait_for_event@24 = libusb_wait_for_event
+ libusb_handle_events_timeout_check@24 = libusb_handle_events_timeout_check
+ libusb_handle_events_timeout@24 = libusb_handle_events_timeout
+ libusb_handle_events_check@24 = libusb_handle_events_check
+ libusb_handle_events@24 = libusb_handle_events
+ libusb_handle_events_locked@24 = libusb_handle_events_locked
+ libusb_pollfds_handle_timeouts@24 = libusb_pollfds_handle_timeouts
+ libusb_get_next_timeout@24 = libusb_get_next_timeout
+ libusb_set_pollfd_notifiers@24 = libusb_set_pollfd_notifiers
+ libusb_control_transfer@24 = libusb_control_transfer
+ libusb_bulk_transfer@24 = libusb_bulk_transfer
+ libusb_interrupt_transfer@24 = libusb_interrupt_transfer
+ libusb_ref_device@24 = libusb_ref_device
+ libusb_open_device_with_vid_pid@24 = libusb_open_device_with_vid_pid
+ libusb_get_device@24 = libusb_get_device
+ libusb_strerror@24 = libusb_strerror
+ libusb_getversion@24 = libusb_getversion
+ libusb_alloc_transfer@24 = libusb_alloc_transfer
+ libusb_get_pollfds@24 = libusb_get_pollfds
+ libusb_get_device_list@28 = libusb_get_device_list
+ libusb_free_device_list@28 = libusb_free_device_list
+ libusb_get_bus_number@28 = libusb_get_bus_number
+ libusb_get_device_address@28 = libusb_get_device_address
+ libusb_get_max_packet_size@28 = libusb_get_max_packet_size
+ libusb_get_max_iso_packet_size@28 = libusb_get_max_iso_packet_size
+ libusb_unref_device@28 = libusb_unref_device
+ libusb_open@28 = libusb_open
+ libusb_close@28 = libusb_close
+ libusb_get_configuration@28 = libusb_get_configuration
+ libusb_set_configuration@28 = libusb_set_configuration
+ libusb_claim_interface@28 = libusb_claim_interface
+ libusb_release_interface@28 = libusb_release_interface
+ libusb_set_interface_alt_setting@28 = libusb_set_interface_alt_setting
+ libusb_clear_halt@28 = libusb_clear_halt
+ libusb_reset_device@28 = libusb_reset_device
+ libusb_kernel_driver_active@28 = libusb_kernel_driver_active
+ libusb_detach_kernel_driver@28 = libusb_detach_kernel_driver
+ libusb_attach_kernel_driver@28 = libusb_attach_kernel_driver
+ libusb_set_debug@28 = libusb_set_debug
+ libusb_init@28 = libusb_init
+ libusb_exit@28 = libusb_exit
+ libusb_get_device_descriptor@28 = libusb_get_device_descriptor
+ libusb_get_active_config_descriptor@28 = libusb_get_active_config_descriptor
+ libusb_get_config_descriptor@28 = libusb_get_config_descriptor
+ libusb_get_config_descriptor_by_value@28 = libusb_get_config_descriptor_by_value
+ libusb_free_config_descriptor@28 = libusb_free_config_descriptor
+ libusb_get_string_descriptor_ascii@28 = libusb_get_string_descriptor_ascii
+ libusb_free_transfer@28 = libusb_free_transfer
+ libusb_submit_transfer@28 = libusb_submit_transfer
+ libusb_cancel_transfer@28 = libusb_cancel_transfer
+ libusb_try_lock_events@28 = libusb_try_lock_events
+ libusb_lock_events@28 = libusb_lock_events
+ libusb_unlock_events@28 = libusb_unlock_events
+ libusb_event_handling_ok@28 = libusb_event_handling_ok
+ libusb_event_handler_active@28 = libusb_event_handler_active
+ libusb_lock_event_waiters@28 = libusb_lock_event_waiters
+ libusb_unlock_event_waiters@28 = libusb_unlock_event_waiters
+ libusb_wait_for_event@28 = libusb_wait_for_event
+ libusb_handle_events_timeout_check@28 = libusb_handle_events_timeout_check
+ libusb_handle_events_timeout@28 = libusb_handle_events_timeout
+ libusb_handle_events_check@28 = libusb_handle_events_check
+ libusb_handle_events@28 = libusb_handle_events
+ libusb_handle_events_locked@28 = libusb_handle_events_locked
+ libusb_pollfds_handle_timeouts@28 = libusb_pollfds_handle_timeouts
+ libusb_get_next_timeout@28 = libusb_get_next_timeout
+ libusb_set_pollfd_notifiers@28 = libusb_set_pollfd_notifiers
+ libusb_control_transfer@28 = libusb_control_transfer
+ libusb_bulk_transfer@28 = libusb_bulk_transfer
+ libusb_interrupt_transfer@28 = libusb_interrupt_transfer
+ libusb_ref_device@28 = libusb_ref_device
+ libusb_open_device_with_vid_pid@28 = libusb_open_device_with_vid_pid
+ libusb_get_device@28 = libusb_get_device
+ libusb_strerror@28 = libusb_strerror
+ libusb_getversion@28 = libusb_getversion
+ libusb_alloc_transfer@28 = libusb_alloc_transfer
+ libusb_get_pollfds@28 = libusb_get_pollfds
+ libusb_get_device_list@32 = libusb_get_device_list
+ libusb_free_device_list@32 = libusb_free_device_list
+ libusb_get_bus_number@32 = libusb_get_bus_number
+ libusb_get_device_address@32 = libusb_get_device_address
+ libusb_get_max_packet_size@32 = libusb_get_max_packet_size
+ libusb_get_max_iso_packet_size@32 = libusb_get_max_iso_packet_size
+ libusb_unref_device@32 = libusb_unref_device
+ libusb_open@32 = libusb_open
+ libusb_close@32 = libusb_close
+ libusb_get_configuration@32 = libusb_get_configuration
+ libusb_set_configuration@32 = libusb_set_configuration
+ libusb_claim_interface@32 = libusb_claim_interface
+ libusb_release_interface@32 = libusb_release_interface
+ libusb_set_interface_alt_setting@32 = libusb_set_interface_alt_setting
+ libusb_clear_halt@32 = libusb_clear_halt
+ libusb_reset_device@32 = libusb_reset_device
+ libusb_kernel_driver_active@32 = libusb_kernel_driver_active
+ libusb_detach_kernel_driver@32 = libusb_detach_kernel_driver
+ libusb_attach_kernel_driver@32 = libusb_attach_kernel_driver
+ libusb_set_debug@32 = libusb_set_debug
+ libusb_init@32 = libusb_init
+ libusb_exit@32 = libusb_exit
+ libusb_get_device_descriptor@32 = libusb_get_device_descriptor
+ libusb_get_active_config_descriptor@32 = libusb_get_active_config_descriptor
+ libusb_get_config_descriptor@32 = libusb_get_config_descriptor
+ libusb_get_config_descriptor_by_value@32 = libusb_get_config_descriptor_by_value
+ libusb_free_config_descriptor@32 = libusb_free_config_descriptor
+ libusb_get_string_descriptor_ascii@32 = libusb_get_string_descriptor_ascii
+ libusb_free_transfer@32 = libusb_free_transfer
+ libusb_submit_transfer@32 = libusb_submit_transfer
+ libusb_cancel_transfer@32 = libusb_cancel_transfer
+ libusb_try_lock_events@32 = libusb_try_lock_events
+ libusb_lock_events@32 = libusb_lock_events
+ libusb_unlock_events@32 = libusb_unlock_events
+ libusb_event_handling_ok@32 = libusb_event_handling_ok
+ libusb_event_handler_active@32 = libusb_event_handler_active
+ libusb_lock_event_waiters@32 = libusb_lock_event_waiters
+ libusb_unlock_event_waiters@32 = libusb_unlock_event_waiters
+ libusb_wait_for_event@32 = libusb_wait_for_event
+ libusb_handle_events_timeout_check@32 = libusb_handle_events_timeout_check
+ libusb_handle_events_timeout@32 = libusb_handle_events_timeout
+ libusb_handle_events_check@32 = libusb_handle_events_check
+ libusb_handle_events@32 = libusb_handle_events
+ libusb_handle_events_locked@32 = libusb_handle_events_locked
+ libusb_pollfds_handle_timeouts@32 = libusb_pollfds_handle_timeouts
+ libusb_get_next_timeout@32 = libusb_get_next_timeout
+ libusb_set_pollfd_notifiers@32 = libusb_set_pollfd_notifiers
+ libusb_control_transfer@32 = libusb_control_transfer
+ libusb_bulk_transfer@32 = libusb_bulk_transfer
+ libusb_interrupt_transfer@32 = libusb_interrupt_transfer
+ libusb_ref_device@32 = libusb_ref_device
+ libusb_open_device_with_vid_pid@32 = libusb_open_device_with_vid_pid
+ libusb_get_device@32 = libusb_get_device
+ libusb_strerror@32 = libusb_strerror
+ libusb_getversion@32 = libusb_getversion
+ libusb_alloc_transfer@32 = libusb_alloc_transfer
+ libusb_get_pollfds@32 = libusb_get_pollfds
diff --git a/libusb-1.0/libusb/libusb-1.0.rc b/libusb-1.0/libusb/libusb-1.0.rc
new file mode 100644
index 0000000..d579653
--- /dev/null
+++ b/libusb-1.0/libusb/libusb-1.0.rc
@@ -0,0 +1,50 @@
+/*
+ * For Windows: input this file to the Resoure Compiler to produce a binary
+ * .res file. This is then embedded in the resultant library (like any other
+ * compilation object).
+ * The information can then be queried using standard APIs and can also be
+ * viewed with utilities such as Windows Explorer.
+ */
+#include "winresrc.h"
+#include "libusb_version.h"
+
+#define __DEFTOSTR(x) #x
+#define _DEFTOSTR(x) __DEFTOSTR(x)
+#define LIBUSB_PACKAGE_VERSION _DEFTOSTR(LIBUSB_VERSION_MAJOR.LIBUSB_VERSION_MINOR.LIBUSB_VERSION_MICRO.LIBUSB_VERSION_NANO)
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION LIBUSB_VERSION_MAJOR,LIBUSB_VERSION_MINOR,LIBUSB_VERSION_MICRO,LIBUSB_VERSION_NANO
+ PRODUCTVERSION LIBUSB_VERSION_MAJOR,LIBUSB_VERSION_MINOR,LIBUSB_VERSION_MICRO,LIBUSB_VERSION_NANO
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "Comments", "http://libusb.org/\0"
+ VALUE "CompanyName", "libusb.org\0"
+ VALUE "FileDescription", "libusb-1\0"
+ VALUE "FileVersion", LIBUSB_PACKAGE_VERSION "\0"
+ VALUE "InternalName", "libusb\0"
+ VALUE "LegalCopyright", "See individual source files, GNU LGPL v2.1 or later.\0"
+ VALUE "LegalTrademarks", "http://www.gnu.org/licenses/lgpl-2.1.html\0"
+ VALUE "OriginalFilename", "libusb-1.0.dll\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "libusb-1\0"
+ VALUE "ProductVersion", LIBUSB_PACKAGE_VERSION "\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/libusb-1.0/libusb/libusb.h b/libusb-1.0/libusb/libusb.h
new file mode 100644
index 0000000..72917ca
--- /dev/null
+++ b/libusb-1.0/libusb/libusb.h
@@ -0,0 +1,1353 @@
+/*
+ * Public libusb header file
+ * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LIBUSB_H__
+#define __LIBUSB_H__
+
+#ifdef _MSC_VER
+/* on MS environments, the inline keyword is available in C++ only */
+#define inline __inline
+/* ssize_t is also not available (copy/paste from MinGW) */
+#ifndef _SSIZE_T_DEFINED
+#define _SSIZE_T_DEFINED
+#undef ssize_t
+#ifdef _WIN64
+ typedef __int64 ssize_t;
+#else
+ typedef int ssize_t;
+#endif /* _WIN64 */
+#endif /* _SSIZE_T_DEFINED */
+#endif /* _MSC_VER */
+
+/* stdint.h is also not usually available on MS */
+#if defined(_MSC_VER) && (_MSC_VER < 1600) && (!defined(_STDINT)) && (!defined(_STDINT_H))
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+#else
+#include <stdint.h>
+#endif
+
+#include <sys/types.h>
+#include <time.h>
+#include <limits.h>
+
+#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__)
+#include <sys/time.h>
+#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
+ * As this can be problematic if you include windows.h after libusb.h
+ * in your sources, we force windows.h to be included first. */
+#if defined(_WIN32) || defined(__CYGWIN__)
+#include <windows.h>
+#if defined(interface)
+#undef interface
+#endif
+#endif
+
+/** \def LIBUSB_CALL
+ * \ingroup misc
+ * libusb's Windows calling convention.
+ *
+ * Under Windows, the selection of available compilers and configurations
+ * means that, unlike other platforms, there is not <em>one true calling
+ * convention</em> (calling convention: the manner in which parameters are
+ * passed to funcions in the generated assembly code).
+ *
+ * Matching the Windows API itself, libusb uses the WINAPI convention (which
+ * translates to the <tt>stdcall</tt> convention) and guarantees that the
+ * library is compiled in this way. The public header file also includes
+ * appropriate annotations so that your own software will use the right
+ * convention, even if another convention is being used by default within
+ * your codebase.
+ *
+ * The one consideration that you must apply in your software is to mark
+ * all functions which you use as libusb callbacks with this LIBUSB_CALL
+ * annotation, so that they too get compiled for the correct calling
+ * convention.
+ *
+ * On non-Windows operating systems, this macro is defined as nothing. This
+ * means that you can apply it to your code without worrying about
+ * cross-platform compatibility.
+ */
+/* LIBUSB_CALL must be defined on both definition and declaration of libusb
+ * functions. You'd think that declaration would be enough, but cygwin will
+ * complain about conflicting types unless both are marked this way.
+ * The placement of this macro is important too; it must appear after the
+ * return type, before the function name. See internal documentation for
+ * API_EXPORTED.
+ */
+#if defined(_WIN32) || defined(__CYGWIN__)
+#define LIBUSB_CALL WINAPI
+#else
+#define LIBUSB_CALL
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \def libusb_cpu_to_le16
+ * \ingroup misc
+ * Convert a 16-bit value from host-endian to little-endian format. On
+ * little endian systems, this function does nothing. On big endian systems,
+ * the bytes are swapped.
+ * \param x the host-endian value to convert
+ * \returns the value in little-endian byte order
+ */
+static inline uint16_t libusb_cpu_to_le16(const uint16_t x)
+{
+ union {
+ uint8_t b8[2];
+ uint16_t b16;
+ } _tmp;
+ _tmp.b8[1] = x >> 8;
+ _tmp.b8[0] = x & 0xff;
+ return _tmp.b16;
+}
+
+/** \def libusb_le16_to_cpu
+ * \ingroup misc
+ * Convert a 16-bit value from little-endian to host-endian format. On
+ * little endian systems, this function does nothing. On big endian systems,
+ * the bytes are swapped.
+ * \param x the little-endian value to convert
+ * \returns the value in host-endian byte order
+ */
+#define libusb_le16_to_cpu libusb_cpu_to_le16
+
+/* standard USB stuff */
+
+/** \ingroup desc
+ * Device and/or Interface Class codes */
+enum libusb_class_code {
+ /** In the context of a \ref libusb_device_descriptor "device descriptor",
+ * this bDeviceClass value indicates that each interface specifies its
+ * own class information and all interfaces operate independently.
+ */
+ LIBUSB_CLASS_PER_INTERFACE = 0,
+
+ /** Audio class */
+ LIBUSB_CLASS_AUDIO = 1,
+
+ /** Communications class */
+ LIBUSB_CLASS_COMM = 2,
+
+ /** Human Interface Device class */
+ LIBUSB_CLASS_HID = 3,
+
+ /** Printer dclass */
+ LIBUSB_CLASS_PRINTER = 7,
+
+ /** Picture transfer protocol class */
+ LIBUSB_CLASS_PTP = 6,
+
+ /** Mass storage class */
+ LIBUSB_CLASS_MASS_STORAGE = 8,
+
+ /** Hub class */
+ LIBUSB_CLASS_HUB = 9,
+
+ /** Data class */
+ LIBUSB_CLASS_DATA = 10,
+
+ /** Wireless class */
+ LIBUSB_CLASS_WIRELESS = 0xe0,
+
+ /** Application class */
+ LIBUSB_CLASS_APPLICATION = 0xfe,
+
+ /** Class is vendor-specific */
+ LIBUSB_CLASS_VENDOR_SPEC = 0xff
+};
+
+/** \ingroup desc
+ * Descriptor types as defined by the USB specification. */
+enum libusb_descriptor_type {
+ /** Device descriptor. See libusb_device_descriptor. */
+ LIBUSB_DT_DEVICE = 0x01,
+
+ /** Configuration descriptor. See libusb_config_descriptor. */
+ LIBUSB_DT_CONFIG = 0x02,
+
+ /** String descriptor */
+ LIBUSB_DT_STRING = 0x03,
+
+ /** Interface descriptor. See libusb_interface_descriptor. */
+ LIBUSB_DT_INTERFACE = 0x04,
+
+ /** Endpoint descriptor. See libusb_endpoint_descriptor. */
+ LIBUSB_DT_ENDPOINT = 0x05,
+
+ /** HID descriptor */
+ LIBUSB_DT_HID = 0x21,
+
+ /** HID report descriptor */
+ LIBUSB_DT_REPORT = 0x22,
+
+ /** Physical descriptor */
+ LIBUSB_DT_PHYSICAL = 0x23,
+
+ /** Hub descriptor */
+ LIBUSB_DT_HUB = 0x29
+};
+
+/* Descriptor sizes per descriptor type */
+#define LIBUSB_DT_DEVICE_SIZE 18
+#define LIBUSB_DT_CONFIG_SIZE 9
+#define LIBUSB_DT_INTERFACE_SIZE 9
+#define LIBUSB_DT_ENDPOINT_SIZE 7
+#define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
+#define LIBUSB_DT_HUB_NONVAR_SIZE 7
+
+#define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
+#define LIBUSB_ENDPOINT_DIR_MASK 0x80
+
+/** \ingroup desc
+ * Endpoint direction. Values for bit 7 of the
+ * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme.
+ */
+enum libusb_endpoint_direction {
+ /** In: device-to-host */
+ LIBUSB_ENDPOINT_IN = 0x80,
+
+ /** Out: host-to-device */
+ LIBUSB_ENDPOINT_OUT = 0x00
+};
+
+#define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */
+
+/** \ingroup desc
+ * Endpoint transfer type. Values for bits 0:1 of the
+ * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field.
+ */
+enum libusb_transfer_type {
+ /** Control endpoint */
+ LIBUSB_TRANSFER_TYPE_CONTROL = 0,
+
+ /** Isochronous endpoint */
+ LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1,
+
+ /** Bulk endpoint */
+ LIBUSB_TRANSFER_TYPE_BULK = 2,
+
+ /** Interrupt endpoint */
+ LIBUSB_TRANSFER_TYPE_INTERRUPT = 3
+};
+
+/** \ingroup misc
+ * Standard requests, as defined in table 9-3 of the USB2 specifications */
+enum libusb_standard_request {
+ /** Request status of the specific recipient */
+ LIBUSB_REQUEST_GET_STATUS = 0x00,
+
+ /** Clear or disable a specific feature */
+ LIBUSB_REQUEST_CLEAR_FEATURE = 0x01,
+
+ /* 0x02 is reserved */
+
+ /** Set or enable a specific feature */
+ LIBUSB_REQUEST_SET_FEATURE = 0x03,
+
+ /* 0x04 is reserved */
+
+ /** Set device address for all future accesses */
+ LIBUSB_REQUEST_SET_ADDRESS = 0x05,
+
+ /** Get the specified descriptor */
+ LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06,
+
+ /** Used to update existing descriptors or add new descriptors */
+ LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07,
+
+ /** Get the current device configuration value */
+ LIBUSB_REQUEST_GET_CONFIGURATION = 0x08,
+
+ /** Set device configuration */
+ LIBUSB_REQUEST_SET_CONFIGURATION = 0x09,
+
+ /** Return the selected alternate setting for the specified interface */
+ LIBUSB_REQUEST_GET_INTERFACE = 0x0A,
+
+ /** Select an alternate interface for the specified interface */
+ LIBUSB_REQUEST_SET_INTERFACE = 0x0B,
+
+ /** Set then report an endpoint's synchronization frame */
+ LIBUSB_REQUEST_SYNCH_FRAME = 0x0C
+};
+
+/** \ingroup misc
+ * Request type bits of the
+ * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control
+ * transfers. */
+enum libusb_request_type {
+ /** Standard */
+ LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5),
+
+ /** Class */
+ LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5),
+
+ /** Vendor */
+ LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5),
+
+ /** Reserved */
+ LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5)
+};
+
+/** \ingroup misc
+ * Recipient bits of the
+ * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control
+ * transfers. Values 4 through 31 are reserved. */
+enum libusb_request_recipient {
+ /** Device */
+ LIBUSB_RECIPIENT_DEVICE = 0x00,
+
+ /** Interface */
+ LIBUSB_RECIPIENT_INTERFACE = 0x01,
+
+ /** Endpoint */
+ LIBUSB_RECIPIENT_ENDPOINT = 0x02,
+
+ /** Other */
+ LIBUSB_RECIPIENT_OTHER = 0x03
+};
+
+#define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C
+
+/** \ingroup desc
+ * Synchronization type for isochronous endpoints. Values for bits 2:3 of the
+ * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in
+ * libusb_endpoint_descriptor.
+ */
+enum libusb_iso_sync_type {
+ /** No synchronization */
+ LIBUSB_ISO_SYNC_TYPE_NONE = 0,
+
+ /** Asynchronous */
+ LIBUSB_ISO_SYNC_TYPE_ASYNC = 1,
+
+ /** Adaptive */
+ LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2,
+
+ /** Synchronous */
+ LIBUSB_ISO_SYNC_TYPE_SYNC = 3
+};
+
+#define LIBUSB_ISO_USAGE_TYPE_MASK 0x30
+
+/** \ingroup desc
+ * Usage type for isochronous endpoints. Values for bits 4:5 of the
+ * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in
+ * libusb_endpoint_descriptor.
+ */
+enum libusb_iso_usage_type {
+ /** Data endpoint */
+ LIBUSB_ISO_USAGE_TYPE_DATA = 0,
+
+ /** Feedback endpoint */
+ LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1,
+
+ /** Implicit feedback Data endpoint */
+ LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2
+};
+
+/** \ingroup desc
+ * A structure representing the standard USB device descriptor. This
+ * descriptor is documented in section 9.6.1 of the USB 2.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_device_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this
+ * context. */
+ uint8_t bDescriptorType;
+
+ /** USB specification release number in binary-coded decimal. A value of
+ * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */
+ uint16_t bcdUSB;
+
+ /** USB-IF class code for the device. See \ref libusb_class_code. */
+ uint8_t bDeviceClass;
+
+ /** USB-IF subclass code for the device, qualified by the bDeviceClass
+ * value */
+ uint8_t bDeviceSubClass;
+
+ /** USB-IF protocol code for the device, qualified by the bDeviceClass and
+ * bDeviceSubClass values */
+ uint8_t bDeviceProtocol;
+
+ /** Maximum packet size for endpoint 0 */
+ uint8_t bMaxPacketSize0;
+
+ /** USB-IF vendor ID */
+ uint16_t idVendor;
+
+ /** USB-IF product ID */
+ uint16_t idProduct;
+
+ /** Device release number in binary-coded decimal */
+ uint16_t bcdDevice;
+
+ /** Index of string descriptor describing manufacturer */
+ uint8_t iManufacturer;
+
+ /** Index of string descriptor describing product */
+ uint8_t iProduct;
+
+ /** Index of string descriptor containing device serial number */
+ uint8_t iSerialNumber;
+
+ /** Number of possible configurations */
+ uint8_t bNumConfigurations;
+};
+
+/** \ingroup desc
+ * A structure representing the standard USB endpoint descriptor. This
+ * descriptor is documented in section 9.6.3 of the USB 2.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_endpoint_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in
+ * this context. */
+ uint8_t bDescriptorType;
+
+ /** The address of the endpoint described by this descriptor. Bits 0:3 are
+ * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction,
+ * see \ref libusb_endpoint_direction.
+ */
+ uint8_t bEndpointAddress;
+
+ /** Attributes which apply to the endpoint when it is configured using
+ * the bConfigurationValue. Bits 0:1 determine the transfer type and
+ * correspond to \ref libusb_transfer_type. Bits 2:3 are only used for
+ * isochronous endpoints and correspond to \ref libusb_iso_sync_type.
+ * Bits 4:5 are also only used for isochronous endpoints and correspond to
+ * \ref libusb_iso_usage_type. Bits 6:7 are reserved.
+ */
+ uint8_t bmAttributes;
+
+ /** Maximum packet size this endpoint is capable of sending/receiving. */
+ uint16_t wMaxPacketSize;
+
+ /** Interval for polling endpoint for data transfers. */
+ uint8_t bInterval;
+
+ /** For audio devices only: the rate at which synchronization feedback
+ * is provided. */
+ uint8_t bRefresh;
+
+ /** For audio devices only: the address if the synch endpoint */
+ uint8_t bSynchAddress;
+
+ /** Extra descriptors. If libusb encounters unknown endpoint descriptors,
+ * it will store them here, should you wish to parse them. */
+ const unsigned char *extra;
+
+ /** Length of the extra descriptors, in bytes. */
+ int extra_length;
+};
+
+/** \ingroup desc
+ * A structure representing the standard USB interface descriptor. This
+ * descriptor is documented in section 9.6.5 of the USB 2.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_interface_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE
+ * in this context. */
+ uint8_t bDescriptorType;
+
+ /** Number of this interface */
+ uint8_t bInterfaceNumber;
+
+ /** Value used to select this alternate setting for this interface */
+ uint8_t bAlternateSetting;
+
+ /** Number of endpoints used by this interface (excluding the control
+ * endpoint). */
+ uint8_t bNumEndpoints;
+
+ /** USB-IF class code for this interface. See \ref libusb_class_code. */
+ uint8_t bInterfaceClass;
+
+ /** USB-IF subclass code for this interface, qualified by the
+ * bInterfaceClass value */
+ uint8_t bInterfaceSubClass;
+
+ /** USB-IF protocol code for this interface, qualified by the
+ * bInterfaceClass and bInterfaceSubClass values */
+ uint8_t bInterfaceProtocol;
+
+ /** Index of string descriptor describing this interface */
+ uint8_t iInterface;
+
+ /** Array of endpoint descriptors. This length of this array is determined
+ * by the bNumEndpoints field. */
+ const struct libusb_endpoint_descriptor *endpoint;
+
+ /** Extra descriptors. If libusb encounters unknown interface descriptors,
+ * it will store them here, should you wish to parse them. */
+ const unsigned char *extra;
+
+ /** Length of the extra descriptors, in bytes. */
+ int extra_length;
+};
+
+/** \ingroup desc
+ * A collection of alternate settings for a particular USB interface.
+ */
+struct libusb_interface {
+ /** Array of interface descriptors. The length of this array is determined
+ * by the num_altsetting field. */
+ const struct libusb_interface_descriptor *altsetting;
+
+ /** The number of alternate settings that belong to this interface */
+ int num_altsetting;
+};
+
+/** \ingroup desc
+ * A structure representing the standard USB configuration descriptor. This
+ * descriptor is documented in section 9.6.3 of the USB 2.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_config_descriptor {
+ /** Size of this descriptor (in bytes) */
+ uint8_t bLength;
+
+ /** Descriptor type. Will have value
+ * \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG
+ * in this context. */
+ uint8_t bDescriptorType;
+
+ /** Total length of data returned for this configuration */
+ uint16_t wTotalLength;
+
+ /** Number of interfaces supported by this configuration */
+ uint8_t bNumInterfaces;
+
+ /** Identifier value for this configuration */
+ uint8_t bConfigurationValue;
+
+ /** Index of string descriptor describing this configuration */
+ uint8_t iConfiguration;
+
+ /** Configuration characteristics */
+ uint8_t bmAttributes;
+
+ /** Maximum power consumption of the USB device from this bus in this
+ * configuration when the device is fully opreation. Expressed in units
+ * of 2 mA. */
+ uint8_t MaxPower;
+
+ /** Array of interfaces supported by this configuration. The length of
+ * this array is determined by the bNumInterfaces field. */
+ const struct libusb_interface *interface;
+
+ /** Extra descriptors. If libusb encounters unknown configuration
+ * descriptors, it will store them here, should you wish to parse them. */
+ const unsigned char *extra;
+
+ /** Length of the extra descriptors, in bytes. */
+ int extra_length;
+};
+
+/** \ingroup asyncio
+ * Setup packet for control transfers. */
+struct libusb_control_setup {
+ /** Request type. Bits 0:4 determine recipient, see
+ * \ref libusb_request_recipient. Bits 5:6 determine type, see
+ * \ref libusb_request_type. Bit 7 determines data transfer direction, see
+ * \ref libusb_endpoint_direction.
+ */
+ uint8_t bmRequestType;
+
+ /** Request. If the type bits of bmRequestType are equal to
+ * \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD
+ * "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to
+ * \ref libusb_standard_request. For other cases, use of this field is
+ * application-specific. */
+ uint8_t bRequest;
+
+ /** Value. Varies according to request */
+ uint16_t wValue;
+
+ /** Index. Varies according to request, typically used to pass an index
+ * or offset */
+ uint16_t wIndex;
+
+ /** Number of bytes to transfer */
+ uint16_t wLength;
+};
+
+#define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup))
+
+/* libusb */
+
+struct libusb_context;
+struct libusb_device;
+struct libusb_device_handle;
+
+/** \ingroup lib
+ * Structure providing the version of libusb being used
+ */
+struct libusb_version {
+ uint16_t major;
+ uint16_t minor;
+ uint16_t micro;
+ uint16_t nano;
+};
+
+/** \ingroup lib
+ * Structure representing a libusb session. The concept of individual libusb
+ * 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_exit() will not destroy resources that the other user is still
+ * using.
+ *
+ * Sessions are created by libusb_init() and destroyed through libusb_exit().
+ * If your application is guaranteed to only ever include a single libusb
+ * user (i.e. you), you do not have to worry about contexts: pass NULL in
+ * every function call where a context is required. The default context
+ * will be used.
+ *
+ * For more information, see \ref contexts.
+ */
+typedef struct libusb_context libusb_context;
+
+/** \ingroup dev
+ * Structure representing a USB device detected on the system. This is an
+ * opaque type for which you are only ever provided with a pointer, usually
+ * originating from libusb_get_device_list().
+ *
+ * Certain operations can be performed on a device, but in order to do any
+ * I/O you will have to first obtain a device handle using libusb_open().
+ *
+ * Devices are reference counted with libusb_device_ref() and
+ * libusb_device_unref(), and are freed when the reference count reaches 0.
+ * New devices presented by libusb_get_device_list() have a reference count of
+ * 1, and libusb_free_device_list() can optionally decrease the reference count
+ * on all devices in the list. libusb_open() adds another reference which is
+ * later destroyed by libusb_close().
+ */
+typedef struct libusb_device libusb_device;
+
+
+/** \ingroup dev
+ * Structure representing a handle on a USB device. This is an opaque type for
+ * which you are only ever provided with a pointer, usually originating from
+ * libusb_open().
+ *
+ * A device handle is used to perform I/O and other operations. When finished
+ * with a device handle, you should call libusb_close().
+ */
+typedef struct libusb_device_handle libusb_device_handle;
+
+/** \ingroup misc
+ * Error codes. Most libusb functions return 0 on success or one of these
+ * codes on failure.
+ * You can use libusb_strerror() to retrieve a short string description of
+ * a libusb_error enumeration value.
+ */
+enum libusb_error {
+ /** Success (no error) */
+ LIBUSB_SUCCESS = 0,
+
+ /** Input/output error */
+ LIBUSB_ERROR_IO = -1,
+
+ /** Invalid parameter */
+ LIBUSB_ERROR_INVALID_PARAM = -2,
+
+ /** Access denied (insufficient permissions) */
+ LIBUSB_ERROR_ACCESS = -3,
+
+ /** No such device (it may have been disconnected) */
+ LIBUSB_ERROR_NO_DEVICE = -4,
+
+ /** Entity not found */
+ LIBUSB_ERROR_NOT_FOUND = -5,
+
+ /** Resource busy */
+ LIBUSB_ERROR_BUSY = -6,
+
+ /** Operation timed out */
+ LIBUSB_ERROR_TIMEOUT = -7,
+
+ /** Overflow */
+ LIBUSB_ERROR_OVERFLOW = -8,
+
+ /** Pipe error */
+ LIBUSB_ERROR_PIPE = -9,
+
+ /** System call interrupted (perhaps due to signal) */
+ LIBUSB_ERROR_INTERRUPTED = -10,
+
+ /** Insufficient memory */
+ LIBUSB_ERROR_NO_MEM = -11,
+
+ /** Operation not supported or unimplemented on this platform */
+ LIBUSB_ERROR_NOT_SUPPORTED = -12,
+
+ /** Other error */
+ LIBUSB_ERROR_OTHER = -99
+
+ /* IMPORTANT: when adding new values to this enum, remember to
+ update the libusb_strerror() function implementation! */
+};
+
+/** \ingroup asyncio
+ * Transfer status codes */
+enum libusb_transfer_status {
+ /** Transfer completed without error. Note that this does not indicate
+ * that the entire amount of requested data was transferred. */
+ LIBUSB_TRANSFER_COMPLETED,
+
+ /** Transfer failed */
+ LIBUSB_TRANSFER_ERROR,
+
+ /** Transfer timed out */
+ LIBUSB_TRANSFER_TIMED_OUT,
+
+ /** Transfer was cancelled */
+ LIBUSB_TRANSFER_CANCELLED,
+
+ /** For bulk/interrupt endpoints: halt condition detected (endpoint
+ * stalled). For control endpoints: control request not supported. */
+ LIBUSB_TRANSFER_STALL,
+
+ /** Device was disconnected */
+ LIBUSB_TRANSFER_NO_DEVICE,
+
+ /** Device sent more data than requested */
+ LIBUSB_TRANSFER_OVERFLOW
+};
+
+/** \ingroup asyncio
+ * libusb_transfer.flags values */
+enum libusb_transfer_flags {
+ /** Report short frames as errors */
+ LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0,
+
+ /** Automatically free() transfer buffer during libusb_free_transfer() */
+ LIBUSB_TRANSFER_FREE_BUFFER = 1<<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
+};
+
+/** \ingroup asyncio
+ * Isochronous packet descriptor. */
+struct libusb_iso_packet_descriptor {
+ /** Length of data to request in this packet */
+ unsigned int length;
+
+ /** Amount of data that was actually transferred */
+ unsigned int actual_length;
+
+ /** Status code for this packet */
+ enum libusb_transfer_status status;
+};
+
+struct libusb_transfer;
+
+/** \ingroup asyncio
+ * Asynchronous transfer callback function type. When submitting asynchronous
+ * transfers, you pass a pointer to a callback function of this type via the
+ * \ref libusb_transfer::callback "callback" member of the libusb_transfer
+ * structure. libusb will call this function later, when the transfer has
+ * completed or failed. See \ref asyncio for more information.
+ * \param transfer The libusb_transfer struct the callback function is being
+ * notified about.
+ */
+typedef void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer);
+
+/** \ingroup asyncio
+ * The generic USB transfer structure. The user populates this structure and
+ * then submits it in order to request a transfer. After the transfer has
+ * completed, the library populates the transfer with the results and passes
+ * it back to the user.
+ */
+struct libusb_transfer {
+ /** Handle of the device that this transfer will be submitted to */
+ libusb_device_handle *dev_handle;
+
+ /** A bitwise OR combination of \ref libusb_transfer_flags. */
+ uint8_t flags;
+
+ /** Address of the endpoint where this transfer will be sent. */
+ unsigned char endpoint;
+
+ /** 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. */
+ unsigned int timeout;
+
+ /** The status of the transfer. Read-only, and only for use within
+ * transfer callback function.
+ *
+ * If this is an isochronous transfer, this field may read COMPLETED even
+ * if there were errors in the frames. Use the
+ * \ref libusb_iso_packet_descriptor::status "status" field in each packet
+ * to determine if errors occurred. */
+ enum libusb_transfer_status status;
+
+ /** Length of the data buffer */
+ int length;
+
+ /** Actual length of data that was transferred. Read-only, and only for
+ * use within transfer callback function. Not valid for isochronous
+ * endpoint transfers. */
+ int actual_length;
+
+ /** Callback function. This will be invoked when the transfer completes,
+ * fails, or is cancelled. */
+ libusb_transfer_cb_fn callback;
+
+ /** User context data to pass to the callback function. */
+ void *user_data;
+
+ /** Data buffer */
+ unsigned char *buffer;
+
+ /** Number of isochronous packets. Only used for I/O with isochronous
+ * endpoints. */
+ 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
+ ;
+};
+
+int LIBUSB_CALL libusb_init(libusb_context **ctx);
+void LIBUSB_CALL libusb_exit(libusb_context *ctx);
+void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level);
+const char * LIBUSB_CALL libusb_strerror(enum libusb_error errcode);
+const struct libusb_version * LIBUSB_CALL libusb_getversion(void);
+
+ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx,
+ libusb_device ***list);
+void LIBUSB_CALL libusb_free_device_list(libusb_device **list,
+ int unref_devices);
+libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev);
+void LIBUSB_CALL libusb_unref_device(libusb_device *dev);
+
+int LIBUSB_CALL libusb_get_configuration(libusb_device_handle *dev,
+ int *config);
+int LIBUSB_CALL libusb_get_device_descriptor(libusb_device *dev,
+ struct libusb_device_descriptor *desc);
+int LIBUSB_CALL libusb_get_active_config_descriptor(libusb_device *dev,
+ struct libusb_config_descriptor **config);
+int LIBUSB_CALL libusb_get_config_descriptor(libusb_device *dev,
+ uint8_t config_index, struct libusb_config_descriptor **config);
+int LIBUSB_CALL libusb_get_config_descriptor_by_value(libusb_device *dev,
+ uint8_t bConfigurationValue, struct libusb_config_descriptor **config);
+void LIBUSB_CALL libusb_free_config_descriptor(
+ struct libusb_config_descriptor *config);
+uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev);
+uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device *dev);
+int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev,
+ unsigned char endpoint);
+int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev,
+ unsigned char endpoint);
+
+int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle);
+void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle);
+libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle);
+
+int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev,
+ int configuration);
+int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev,
+ int interface_number);
+int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev,
+ int interface_number);
+
+libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid(
+ libusb_context *ctx, uint16_t vendor_id, uint16_t product_id);
+
+int LIBUSB_CALL libusb_set_interface_alt_setting(libusb_device_handle *dev,
+ int interface_number, int alternate_setting);
+int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev,
+ unsigned char endpoint);
+int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev);
+
+int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev,
+ int interface_number);
+int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev,
+ int interface_number);
+int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev,
+ int interface_number);
+
+/* async I/O */
+
+/** \ingroup asyncio
+ * Get the data section of a control transfer. This convenience function is here
+ * to remind you that the data does not start until 8 bytes into the actual
+ * buffer, as the setup packet comes first.
+ *
+ * Calling this function only makes sense from a transfer callback function,
+ * or situations where you have already allocated a suitably sized buffer at
+ * transfer->buffer.
+ *
+ * \param transfer a transfer
+ * \returns pointer to the first byte of the data section
+ */
+static inline unsigned char *libusb_control_transfer_get_data(
+ struct libusb_transfer *transfer)
+{
+ return transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
+}
+
+/** \ingroup asyncio
+ * Get the control setup packet of a control transfer. This convenience
+ * function is here to remind you that the control setup occupies the first
+ * 8 bytes of the transfer data buffer.
+ *
+ * Calling this function only makes sense from a transfer callback function,
+ * or situations where you have already allocated a suitably sized buffer at
+ * transfer->buffer.
+ *
+ * \param transfer a transfer
+ * \returns a casted pointer to the start of the transfer data buffer
+ */
+static inline struct libusb_control_setup *libusb_control_transfer_get_setup(
+ struct libusb_transfer *transfer)
+{
+ return (struct libusb_control_setup *) transfer->buffer;
+}
+
+/** \ingroup asyncio
+ * Helper function to populate the setup packet (first 8 bytes of the data
+ * buffer) for a control transfer. The wIndex, wValue and wLength values should
+ * be given in host-endian byte order.
+ *
+ * \param buffer buffer to output the setup packet into
+ * \param bmRequestType see the
+ * \ref libusb_control_setup::bmRequestType "bmRequestType" field of
+ * \ref libusb_control_setup
+ * \param bRequest see the
+ * \ref libusb_control_setup::bRequest "bRequest" field of
+ * \ref libusb_control_setup
+ * \param wValue see the
+ * \ref libusb_control_setup::wValue "wValue" field of
+ * \ref libusb_control_setup
+ * \param wIndex see the
+ * \ref libusb_control_setup::wIndex "wIndex" field of
+ * \ref libusb_control_setup
+ * \param wLength see the
+ * \ref libusb_control_setup::wLength "wLength" field of
+ * \ref libusb_control_setup
+ */
+static inline void libusb_fill_control_setup(unsigned char *buffer,
+ uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
+ uint16_t wLength)
+{
+ struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer;
+ setup->bmRequestType = bmRequestType;
+ setup->bRequest = bRequest;
+ setup->wValue = libusb_cpu_to_le16(wValue);
+ setup->wIndex = libusb_cpu_to_le16(wIndex);
+ setup->wLength = libusb_cpu_to_le16(wLength);
+}
+
+struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(int iso_packets);
+int LIBUSB_CALL libusb_submit_transfer(struct libusb_transfer *transfer);
+int LIBUSB_CALL libusb_cancel_transfer(struct libusb_transfer *transfer);
+void LIBUSB_CALL libusb_free_transfer(struct libusb_transfer *transfer);
+
+/** \ingroup asyncio
+ * Helper function to populate the required \ref libusb_transfer fields
+ * for a control transfer.
+ *
+ * If you pass a transfer buffer to this function, the first 8 bytes will
+ * be interpreted as a control setup packet, and the wLength field will be
+ * used to automatically populate the \ref libusb_transfer::length "length"
+ * field of the transfer. Therefore the recommended approach is:
+ * -# Allocate a suitably sized data buffer (including space for control setup)
+ * -# Call libusb_fill_control_setup()
+ * -# If this is a host-to-device transfer with a data stage, put the data
+ * in place after the setup packet
+ * -# Call this function
+ * -# Call libusb_submit_transfer()
+ *
+ * It is also legal to pass a NULL buffer to this function, in which case this
+ * function will not attempt to populate the length field. Remember that you
+ * must then populate the buffer and length fields later.
+ *
+ * \param transfer the transfer to populate
+ * \param dev_handle handle of the device that will handle the transfer
+ * \param buffer data buffer. If provided, this function will interpret the
+ * first 8 bytes as a setup packet and infer the transfer length from that.
+ * \param callback callback function to be invoked on transfer completion
+ * \param user_data user data to pass to callback function
+ * \param timeout timeout for the transfer in milliseconds
+ */
+static inline void libusb_fill_control_transfer(
+ struct libusb_transfer *transfer, libusb_device_handle *dev_handle,
+ unsigned char *buffer, libusb_transfer_cb_fn callback, void *user_data,
+ unsigned int timeout)
+{
+ struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer;
+ transfer->dev_handle = dev_handle;
+ transfer->endpoint = 0;
+ transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL;
+ transfer->timeout = timeout;
+ transfer->buffer = buffer;
+ if (setup)
+ transfer->length = LIBUSB_CONTROL_SETUP_SIZE
+ + libusb_le16_to_cpu(setup->wLength);
+ transfer->user_data = user_data;
+ transfer->callback = callback;
+}
+
+/** \ingroup asyncio
+ * Helper function to populate the required \ref libusb_transfer fields
+ * for a bulk transfer.
+ *
+ * \param transfer the transfer to populate
+ * \param dev_handle handle of the device that will handle the transfer
+ * \param endpoint address of the endpoint where this transfer will be sent
+ * \param buffer data buffer
+ * \param length length of data buffer
+ * \param callback callback function to be invoked on transfer completion
+ * \param user_data user data to pass to callback function
+ * \param timeout timeout for the transfer in milliseconds
+ */
+static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer,
+ libusb_device_handle *dev_handle, unsigned char endpoint,
+ unsigned char *buffer, int length, libusb_transfer_cb_fn callback,
+ void *user_data, unsigned int timeout)
+{
+ transfer->dev_handle = dev_handle;
+ transfer->endpoint = endpoint;
+ transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
+ transfer->timeout = timeout;
+ transfer->buffer = buffer;
+ transfer->length = length;
+ transfer->user_data = user_data;
+ transfer->callback = callback;
+}
+
+/** \ingroup asyncio
+ * Helper function to populate the required \ref libusb_transfer fields
+ * for an interrupt transfer.
+ *
+ * \param transfer the transfer to populate
+ * \param dev_handle handle of the device that will handle the transfer
+ * \param endpoint address of the endpoint where this transfer will be sent
+ * \param buffer data buffer
+ * \param length length of data buffer
+ * \param callback callback function to be invoked on transfer completion
+ * \param user_data user data to pass to callback function
+ * \param timeout timeout for the transfer in milliseconds
+ */
+static inline void libusb_fill_interrupt_transfer(
+ struct libusb_transfer *transfer, libusb_device_handle *dev_handle,
+ unsigned char endpoint, unsigned char *buffer, int length,
+ libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout)
+{
+ transfer->dev_handle = dev_handle;
+ transfer->endpoint = endpoint;
+ transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
+ transfer->timeout = timeout;
+ transfer->buffer = buffer;
+ transfer->length = length;
+ transfer->user_data = user_data;
+ transfer->callback = callback;
+}
+
+/** \ingroup asyncio
+ * Helper function to populate the required \ref libusb_transfer fields
+ * for an isochronous transfer.
+ *
+ * \param transfer the transfer to populate
+ * \param dev_handle handle of the device that will handle the transfer
+ * \param endpoint address of the endpoint where this transfer will be sent
+ * \param buffer data buffer
+ * \param length length of data buffer
+ * \param num_iso_packets the number of isochronous packets
+ * \param callback callback function to be invoked on transfer completion
+ * \param user_data user data to pass to callback function
+ * \param timeout timeout for the transfer in milliseconds
+ */
+static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer,
+ libusb_device_handle *dev_handle, unsigned char endpoint,
+ unsigned char *buffer, int length, int num_iso_packets,
+ libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout)
+{
+ transfer->dev_handle = dev_handle;
+ transfer->endpoint = endpoint;
+ transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
+ transfer->timeout = timeout;
+ transfer->buffer = buffer;
+ transfer->length = length;
+ transfer->num_iso_packets = num_iso_packets;
+ transfer->user_data = user_data;
+ transfer->callback = callback;
+}
+
+/** \ingroup asyncio
+ * Convenience function to set the length of all packets in an isochronous
+ * transfer, based on the num_iso_packets field in the transfer structure.
+ *
+ * \param transfer a transfer
+ * \param length the length to set in each isochronous packet descriptor
+ * \see libusb_get_max_packet_size()
+ */
+static inline void libusb_set_iso_packet_lengths(
+ struct libusb_transfer *transfer, unsigned int length)
+{
+ int i;
+ for (i = 0; i < transfer->num_iso_packets; i++)
+ transfer->iso_packet_desc[i].length = length;
+}
+
+/** \ingroup asyncio
+ * Convenience function to locate the position of an isochronous packet
+ * within the buffer of an isochronous transfer.
+ *
+ * This is a thorough function which loops through all preceding packets,
+ * accumulating their lengths to find the position of the specified packet.
+ * Typically you will assign equal lengths to each packet in the transfer,
+ * and hence the above method is sub-optimal. You may wish to use
+ * libusb_get_iso_packet_buffer_simple() instead.
+ *
+ * \param transfer a transfer
+ * \param packet the packet to return the address of
+ * \returns the base address of the packet buffer inside the transfer buffer,
+ * or NULL if the packet does not exist.
+ * \see libusb_get_iso_packet_buffer_simple()
+ */
+static inline unsigned char *libusb_get_iso_packet_buffer(
+ struct libusb_transfer *transfer, unsigned int packet)
+{
+ int i;
+ size_t offset = 0;
+ int _packet;
+
+ /* oops..slight bug in the API. packet is an unsigned int, but we use
+ * signed integers almost everywhere else. range-check and convert to
+ * signed to avoid compiler warnings. FIXME for libusb-2. */
+ if (packet > INT_MAX)
+ return NULL;
+ _packet = packet;
+
+ if (_packet >= transfer->num_iso_packets)
+ return NULL;
+
+ for (i = 0; i < _packet; i++)
+ offset += transfer->iso_packet_desc[i].length;
+
+ return transfer->buffer + offset;
+}
+
+/** \ingroup asyncio
+ * Convenience function to locate the position of an isochronous packet
+ * within the buffer of an isochronous transfer, for transfers where each
+ * packet is of identical size.
+ *
+ * This function relies on the assumption that every packet within the transfer
+ * is of identical size to the first packet. Calculating the location of
+ * the packet buffer is then just a simple calculation:
+ * <tt>buffer + (packet_size * packet)</tt>
+ *
+ * Do not use this function on transfers other than those that have identical
+ * packet lengths for each packet.
+ *
+ * \param transfer a transfer
+ * \param packet the packet to return the address of
+ * \returns the base address of the packet buffer inside the transfer buffer,
+ * or NULL if the packet does not exist.
+ * \see libusb_get_iso_packet_buffer()
+ */
+static inline unsigned char *libusb_get_iso_packet_buffer_simple(
+ struct libusb_transfer *transfer, unsigned int packet)
+{
+ int _packet;
+
+ /* oops..slight bug in the API. packet is an unsigned int, but we use
+ * signed integers almost everywhere else. range-check and convert to
+ * signed to avoid compiler warnings. FIXME for libusb-2. */
+ if (packet > INT_MAX)
+ return NULL;
+ _packet = packet;
+
+ if (_packet >= transfer->num_iso_packets)
+ return NULL;
+
+ return transfer->buffer + (transfer->iso_packet_desc[0].length * _packet);
+}
+
+/* sync I/O */
+
+int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle,
+ uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
+ unsigned char *data, uint16_t wLength, unsigned int timeout);
+
+int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle,
+ unsigned char endpoint, unsigned char *data, int length,
+ int *actual_length, unsigned int timeout);
+
+int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle,
+ unsigned char endpoint, unsigned char *data, int length,
+ int *actual_length, unsigned int timeout);
+
+/** \ingroup desc
+ * Retrieve a descriptor from the default control pipe.
+ * This is a convenience function which formulates the appropriate control
+ * message to retrieve the descriptor.
+ *
+ * \param dev a device handle
+ * \param desc_type the descriptor type, see \ref libusb_descriptor_type
+ * \param desc_index the index of the descriptor to retrieve
+ * \param data output buffer for descriptor
+ * \param length size of data buffer
+ * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure
+ */
+static inline int libusb_get_descriptor(libusb_device_handle *dev,
+ uint8_t desc_type, uint8_t desc_index, unsigned char *data, int length)
+{
+ return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN,
+ LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data,
+ (uint16_t) length, 1000);
+}
+
+/** \ingroup desc
+ * Retrieve a descriptor from a device.
+ * This is a convenience function which formulates the appropriate control
+ * message to retrieve the descriptor. The string returned is Unicode, as
+ * detailed in the USB specifications.
+ *
+ * \param dev a device handle
+ * \param desc_index the index of the descriptor to retrieve
+ * \param langid the language ID for the string descriptor
+ * \param data output buffer for descriptor
+ * \param length size of data buffer
+ * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure
+ * \see libusb_get_string_descriptor_ascii()
+ */
+static inline int libusb_get_string_descriptor(libusb_device_handle *dev,
+ uint8_t desc_index, uint16_t langid, unsigned char *data, int length)
+{
+ return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN,
+ LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc_index,
+ langid, data, (uint16_t) length, 1000);
+}
+
+int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev,
+ uint8_t desc_index, unsigned char *data, int length);
+
+/* polling and timeouts */
+
+int LIBUSB_CALL libusb_try_lock_events(libusb_context *ctx);
+void LIBUSB_CALL libusb_lock_events(libusb_context *ctx);
+void LIBUSB_CALL libusb_unlock_events(libusb_context *ctx);
+int LIBUSB_CALL libusb_event_handling_ok(libusb_context *ctx);
+int LIBUSB_CALL libusb_event_handler_active(libusb_context *ctx);
+void LIBUSB_CALL libusb_lock_event_waiters(libusb_context *ctx);
+void LIBUSB_CALL libusb_unlock_event_waiters(libusb_context *ctx);
+int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv);
+
+int LIBUSB_CALL libusb_handle_events_timeout(libusb_context *ctx,
+ struct timeval *tv);
+int LIBUSB_CALL libusb_handle_events_timeout_check(libusb_context *ctx,
+ struct timeval *tv, int *completed);
+int LIBUSB_CALL libusb_handle_events(libusb_context *ctx);
+int LIBUSB_CALL libusb_handle_events_check(libusb_context *ctx, int *completed);
+int LIBUSB_CALL libusb_handle_events_locked(libusb_context *ctx,
+ struct timeval *tv);
+int LIBUSB_CALL libusb_pollfds_handle_timeouts(libusb_context *ctx);
+int LIBUSB_CALL libusb_get_next_timeout(libusb_context *ctx,
+ struct timeval *tv);
+
+/** \ingroup poll
+ * File descriptor for polling
+ */
+struct libusb_pollfd {
+ /** Numeric file descriptor */
+ int fd;
+
+ /** Event flags to poll for from <poll.h>. POLLIN indicates that you
+ * should monitor this file descriptor for becoming ready to read from,
+ * and POLLOUT indicates that you should monitor this file descriptor for
+ * nonblocking write readiness. */
+ short events;
+};
+
+/** \ingroup poll
+ * Callback function, invoked when a new file descriptor should be added
+ * to the set of file descriptors monitored for events.
+ * \param fd the new file descriptor
+ * \param events events to monitor for, see \ref libusb_pollfd for a
+ * description
+ * \param user_data User data pointer specified in
+ * libusb_set_pollfd_notifiers() call
+ * \see libusb_set_pollfd_notifiers()
+ */
+typedef void (LIBUSB_CALL *libusb_pollfd_added_cb)(int fd, short events,
+ void *user_data);
+
+/** \ingroup poll
+ * Callback function, invoked when a file descriptor should be removed from
+ * the set of file descriptors being monitored for events. After returning
+ * from this callback, do not use that file descriptor again.
+ * \param fd the file descriptor to stop monitoring
+ * \param user_data User data pointer specified in
+ * libusb_set_pollfd_notifiers() call
+ * \see libusb_set_pollfd_notifiers()
+ */
+typedef void (LIBUSB_CALL *libusb_pollfd_removed_cb)(int fd, void *user_data);
+
+const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds(
+ libusb_context *ctx);
+void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx,
+ libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
+ void *user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libusb-1.0/libusb/libusb_version.h b/libusb-1.0/libusb/libusb_version.h
new file mode 100644
index 0000000..338ba1a
--- /dev/null
+++ b/libusb-1.0/libusb/libusb_version.h
@@ -0,0 +1,29 @@
+/*
+ * Version header for libusb
+ * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LIBUSB_VERSION_H__
+#define __LIBUSB_VERSION_H__
+
+#define LIBUSB_VERSION_MAJOR 1
+#define LIBUSB_VERSION_MINOR 0
+#define LIBUSB_VERSION_MICRO 8
+#define LIBUSB_VERSION_NANO 10323
+
+#endif
diff --git a/libusb-1.0/libusb/libusb_version.h.in b/libusb-1.0/libusb/libusb_version.h.in
new file mode 100644
index 0000000..f27a59a
--- /dev/null
+++ b/libusb-1.0/libusb/libusb_version.h.in
@@ -0,0 +1,29 @@
+/*
+ * Version header for libusb
+ * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LIBUSB_VERSION_H__
+#define __LIBUSB_VERSION_H__
+
+#define LIBUSB_VERSION_MAJOR @LIBUSB_VERSION_MAJOR@
+#define LIBUSB_VERSION_MINOR @LIBUSB_VERSION_MINOR@
+#define LIBUSB_VERSION_MICRO @LIBUSB_VERSION_MICRO@
+#define LIBUSB_VERSION_NANO @LIBUSB_VERSION_NANO@
+
+#endif
diff --git a/libusb-1.0/libusb/libusbi.h b/libusb-1.0/libusb/libusbi.h
new file mode 100644
index 0000000..99bf6ac
--- /dev/null
+++ b/libusb-1.0/libusb/libusbi.h
@@ -0,0 +1,873 @@
+/*
+ * Internal header for libusb
+ * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LIBUSBI_H__
+#define __LIBUSBI_H__
+
+#include <config.h>
+
+#include <stddef.h>
+#include <stdint.h>
+#include <time.h>
+
+#include <libusb.h>
+#include "libusb_version.h"
+
+/* Inside the libusb code, mark all public functions as follows:
+ * return_type API_EXPORTED function_name(params) { ... }
+ * But if the function returns a pointer, mark it as follows:
+ * DEFAULT_VISIBILITY return_type * LIBUSB_CALL function_name(params) { ... }
+ * In the libusb public header, mark all declarations as:
+ * return_type LIBUSB_CALL function_name(params);
+ */
+#define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY
+
+#define DEVICE_DESC_LENGTH 18
+
+#define USB_MAXENDPOINTS 32
+#define USB_MAXINTERFACES 32
+#define USB_MAXCONFIG 8
+
+struct list_head {
+ struct list_head *prev, *next;
+};
+
+/* Get an entry from the list
+ * ptr - the address of this list_head element in "type"
+ * type - the data type that contains "member"
+ * member - the list_head element in "type"
+ */
+#define list_entry(ptr, type, member) \
+ ((type *)((uintptr_t)(ptr) - (uintptr_t)(&((type *)0L)->member)))
+
+/* Get each entry from a list
+ * pos - A structure pointer has a "member" element
+ * head - list head
+ * member - the list_head element in "pos"
+ * type - the type of the first parameter
+ */
+#define list_for_each_entry(pos, head, member, type) \
+ for (pos = list_entry((head)->next, type, member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, type, member))
+
+#define list_for_each_entry_safe(pos, n, head, member, type) \
+ for (pos = list_entry((head)->next, type, member), \
+ n = list_entry(pos->member.next, type, member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, type, member))
+
+#define list_empty(entry) ((entry)->next == (entry))
+
+static inline void list_init(struct list_head *entry)
+{
+ entry->prev = entry->next = entry;
+}
+
+static inline void list_add(struct list_head *entry, struct list_head *head)
+{
+ entry->next = head->next;
+ entry->prev = head;
+
+ head->next->prev = entry;
+ head->next = entry;
+}
+
+static inline void list_add_tail(struct list_head *entry,
+ struct list_head *head)
+{
+ entry->next = head;
+ entry->prev = head->prev;
+
+ head->prev->next = entry;
+ head->prev = entry;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+ entry->next->prev = entry->prev;
+ entry->prev->next = entry->next;
+}
+
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define TIMESPEC_IS_SET(ts) ((ts)->tv_sec != 0 || (ts)->tv_nsec != 0)
+
+enum usbi_log_level {
+ LOG_LEVEL_DEBUG,
+ LOG_LEVEL_INFO,
+ LOG_LEVEL_WARNING,
+ LOG_LEVEL_ERROR,
+};
+
+void usbi_log(struct libusb_context *ctx, enum usbi_log_level level,
+ const char *function, const char *format, ...);
+
+#if !defined(_MSC_VER) || _MSC_VER > 1200
+
+#ifdef ENABLE_LOGGING
+#define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__)
+#else
+#define _usbi_log(ctx, level, ...)
+#endif
+
+#if defined(ENABLE_DEBUG_LOGGING) || defined(INCLUDE_DEBUG_LOGGING)
+#define usbi_dbg(...) _usbi_log(NULL, LOG_LEVEL_DEBUG, __VA_ARGS__)
+#else
+#define usbi_dbg(...)
+#endif
+
+#define usbi_info(ctx, ...) _usbi_log(ctx, LOG_LEVEL_INFO, __VA_ARGS__)
+#define usbi_warn(ctx, ...) _usbi_log(ctx, LOG_LEVEL_WARNING, __VA_ARGS__)
+#define usbi_err(ctx, ...) _usbi_log(ctx, LOG_LEVEL_ERROR, __VA_ARGS__)
+
+#else /* !defined(_MSC_VER) || _MSC_VER > 1200 */
+
+void usbi_log_v(struct libusb_context *ctx, enum usbi_log_level level,
+ const char *function, const char *format, va_list args);
+
+#ifdef ENABLE_LOGGING
+#define LOG_BODY(ctxt, level) \
+{ \
+ va_list args; \
+ va_start (args, format); \
+ usbi_log_v(ctxt, level, "", format, args); \
+ va_end(args); \
+}
+#else
+#define LOG_BODY(ctxt, level) { }
+#endif
+
+static inline void usbi_info(struct libusb_context *ctx, const char *format,
+ ...)
+ LOG_BODY(ctx,LOG_LEVEL_INFO)
+static inline void usbi_warn(struct libusb_context *ctx, const char *format,
+ ...)
+ LOG_BODY(ctx,LOG_LEVEL_WARNING)
+static inline void usbi_err( struct libusb_context *ctx, const char *format,
+ ...)
+ LOG_BODY(ctx,LOG_LEVEL_ERROR)
+
+static inline void usbi_dbg(const char *format, ...)
+#if defined(ENABLE_DEBUG_LOGGING) || defined(INCLUDE_DEBUG_LOGGING)
+ LOG_BODY(NULL,LOG_LEVEL_DEBUG)
+#else
+{ }
+#endif
+
+#endif /* !defined(_MSC_VER) || _MSC_VER > 1200 */
+
+#define USBI_GET_CONTEXT(ctx) if (!(ctx)) (ctx) = usbi_default_context
+#define DEVICE_CTX(dev) ((dev)->ctx)
+#define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev))
+#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle))
+#define ITRANSFER_CTX(transfer) \
+ (TRANSFER_CTX(__USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)))
+
+/* Internal abstractions for thread synchronization and poll */
+#if defined(THREADS_POSIX)
+#include <os/threads_posix.h>
+#elif defined(OS_WINDOWS)
+#include <os/threads_windows.h>
+#endif
+
+#if defined(OS_LINUX) || defined(OS_DARWIN)
+#include <os/poll_posix.h>
+#elif defined(OS_WINDOWS)
+#include <os/poll_windows.h>
+#endif
+
+extern struct libusb_context *usbi_default_context;
+
+struct libusb_context {
+ int debug;
+ int debug_fixed;
+
+ /* internal control pipe, used for interrupting event handling when
+ * something needs to modify poll fds. */
+ int ctrl_pipe[2];
+
+ struct list_head usb_devs;
+ usbi_mutex_t usb_devs_lock;
+
+ /* A list of open handles. Backends are free to traverse this if required.
+ */
+ struct list_head open_devs;
+ usbi_mutex_t open_devs_lock;
+
+ /* this is a list of in-flight transfer handles, sorted by timeout
+ * expiration. URBs to timeout the soonest are placed at the beginning of
+ * the list, URBs that will time out later are placed after, and urbs with
+ * infinite timeout are always placed at the very end. */
+ struct list_head flying_transfers;
+ usbi_mutex_t flying_transfers_lock;
+
+ /* list of poll fds */
+ struct list_head pollfds;
+ usbi_mutex_t pollfds_lock;
+
+ /* a counter that is set when we want to interrupt event handling, in order
+ * to modify the poll fd set. and a lock to protect it. */
+ unsigned int pollfd_modify;
+ usbi_mutex_t pollfd_modify_lock;
+
+ /* user callbacks for pollfd changes */
+ libusb_pollfd_added_cb fd_added_cb;
+ libusb_pollfd_removed_cb fd_removed_cb;
+ void *fd_cb_user_data;
+
+ /* ensures that only one thread is handling events at any one time */
+ usbi_mutex_t events_lock;
+
+ /* used to see if there is an active thread doing event handling */
+ int event_handler_active;
+
+ /* used to wait for event completion in threads other than the one that is
+ * event handling */
+ usbi_mutex_t event_waiters_lock;
+ usbi_cond_t event_waiters_cond;
+
+#ifdef USBI_TIMERFD_AVAILABLE
+ /* used for timeout handling, if supported by OS.
+ * this timerfd is maintained to trigger on the next pending timeout */
+ int timerfd;
+#endif
+};
+
+#ifdef USBI_TIMERFD_AVAILABLE
+#define usbi_using_timerfd(ctx) ((ctx)->timerfd >= 0)
+#else
+#define usbi_using_timerfd(ctx) (0)
+#endif
+
+struct libusb_device {
+ /* lock protects refcnt, everything else is finalized at initialization
+ * time */
+ usbi_mutex_t lock;
+ int refcnt;
+
+ struct libusb_context *ctx;
+
+ uint8_t bus_number;
+ uint8_t device_address;
+ uint8_t num_configurations;
+
+ struct list_head list;
+ unsigned long session_data;
+ unsigned char os_priv[0];
+};
+
+struct libusb_device_handle {
+ /* lock protects claimed_interfaces */
+ usbi_mutex_t lock;
+ unsigned long claimed_interfaces;
+
+ struct list_head list;
+ struct libusb_device *dev;
+ unsigned char os_priv[0];
+};
+
+#define USBI_TRANSFER_TIMED_OUT (1<<0)
+
+enum {
+ USBI_CLOCK_MONOTONIC,
+ USBI_CLOCK_REALTIME
+};
+
+/* in-memory transfer layout:
+ *
+ * 1. struct usbi_transfer
+ * 2. struct libusb_transfer (which includes iso packets) [variable size]
+ * 3. os private data [variable size]
+ *
+ * from a libusb_transfer, you can get the usbi_transfer by rewinding the
+ * appropriate number of bytes.
+ * the usbi_transfer includes the number of allocated packets, so you can
+ * determine the size of the transfer and hence the start and length of the
+ * OS-private data.
+ */
+
+struct usbi_transfer {
+ int num_iso_packets;
+ struct list_head list;
+ struct timeval timeout;
+ int transferred;
+ uint8_t flags;
+
+ /* this lock is held during libusb_submit_transfer() and
+ * libusb_cancel_transfer() (allowing the OS backend to prevent duplicate
+ * cancellation, submission-during-cancellation, etc). the OS backend
+ * should also take this lock in the handle_events path, to prevent the user
+ * cancelling the transfer from another thread while you are processing
+ * its completion (presumably there would be races within your OS backend
+ * if this were possible). */
+ usbi_mutex_t lock;
+};
+
+#define __USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \
+ ((struct libusb_transfer *)(((unsigned char *)(transfer)) \
+ + sizeof(struct usbi_transfer)))
+#define __LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer) \
+ ((struct usbi_transfer *)(((unsigned char *)(transfer)) \
+ - sizeof(struct usbi_transfer)))
+
+static inline void *usbi_transfer_get_os_priv(struct usbi_transfer *transfer)
+{
+ return ((unsigned char *)transfer) + sizeof(struct usbi_transfer)
+ + sizeof(struct libusb_transfer)
+ + (transfer->num_iso_packets
+ * sizeof(struct libusb_iso_packet_descriptor));
+}
+
+/* bus structures */
+
+/* All standard descriptors have these 2 fields in common */
+struct usb_descriptor_header {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+};
+
+/* shared data and functions */
+
+int usbi_io_init(struct libusb_context *ctx);
+void usbi_io_exit(struct libusb_context *ctx);
+
+struct libusb_device *usbi_alloc_device(struct libusb_context *ctx,
+ unsigned long session_id);
+struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx,
+ unsigned long session_id);
+int usbi_sanitize_device(struct libusb_device *dev);
+void usbi_handle_disconnect(struct libusb_device_handle *handle);
+
+int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
+ enum libusb_transfer_status status);
+int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer);
+
+int usbi_parse_descriptor(unsigned char *source, char *descriptor, void *dest,
+ int host_endian);
+int usbi_get_config_index_by_value(struct libusb_device *dev,
+ uint8_t bConfigurationValue, int *idx);
+
+/* polling */
+
+struct usbi_pollfd {
+ /* must come first */
+ struct libusb_pollfd pollfd;
+
+ struct list_head list;
+};
+
+int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events);
+void usbi_remove_pollfd(struct libusb_context *ctx, int fd);
+void usbi_fd_notification(struct libusb_context *ctx);
+
+/* device discovery */
+
+/* we traverse usbfs without knowing how many devices we are going to find.
+ * so we create this discovered_devs model which is similar to a linked-list
+ * which grows when required. it can be freed once discovery has completed,
+ * eliminating the need for a list node in the libusb_device structure
+ * itself. */
+struct discovered_devs {
+ size_t len;
+ size_t capacity;
+ struct libusb_device *devices[0];
+};
+
+struct discovered_devs *discovered_devs_append(
+ struct discovered_devs *discdevs, struct libusb_device *dev);
+
+/* OS abstraction */
+
+/* This is the interface that OS backends need to implement.
+ * All fields are mandatory, except ones explicitly noted as optional. */
+struct usbi_os_backend {
+ /* A human-readable name for your backend, e.g. "Linux usbfs" */
+ const char *name;
+
+ /* Perform initialization of your backend. You might use this function
+ * to determine specific capabilities of the system, allocate required
+ * data structures for later, etc.
+ *
+ * This function is called when a libusb user initializes the library
+ * prior to use.
+ *
+ * Return 0 on success, or a LIBUSB_ERROR code on failure.
+ */
+ int (*init)(struct libusb_context *ctx);
+
+ /* Deinitialization. Optional. This function should destroy anything
+ * that was set up by init.
+ *
+ * This function is called when the user deinitializes the library.
+ */
+ void (*exit)(void);
+
+ /* Enumerate all the USB devices on the system, returning them in a list
+ * of discovered devices.
+ *
+ * Your implementation should enumerate all devices on the system,
+ * regardless of whether they have been seen before or not.
+ *
+ * When you have found a device, compute a session ID for it. The session
+ * ID should uniquely represent that particular device for that particular
+ * connection session since boot (i.e. if you disconnect and reconnect a
+ * device immediately after, it should be assigned a different session ID).
+ * If your OS cannot provide a unique session ID as described above,
+ * presenting a session ID of (bus_number << 8 | device_address) should
+ * be sufficient. Bus numbers and device addresses wrap and get reused,
+ * but that is an unlikely case.
+ *
+ * After computing a session ID for a device, call
+ * usbi_get_device_by_session_id(). This function checks if libusb already
+ * knows about the device, and if so, it provides you with a libusb_device
+ * structure for it.
+ *
+ * If usbi_get_device_by_session_id() returns NULL, it is time to allocate
+ * a new device structure for the device. Call usbi_alloc_device() to
+ * obtain a new libusb_device structure with reference count 1. Populate
+ * the bus_number and device_address attributes of the new device, and
+ * perform any other internal backend initialization you need to do. At
+ * this point, you should be ready to provide device descriptors and so
+ * on through the get_*_descriptor functions. Finally, call
+ * usbi_sanitize_device() to perform some final sanity checks on the
+ * device. Assuming all of the above succeeded, we can now continue.
+ * If any of the above failed, remember to unreference the device that
+ * was returned by usbi_alloc_device().
+ *
+ * At this stage we have a populated libusb_device structure (either one
+ * that was found earlier, or one that we have just allocated and
+ * populated). This can now be added to the discovered devices list
+ * using discovered_devs_append(). Note that discovered_devs_append()
+ * may reallocate the list, returning a new location for it, and also
+ * note that reallocation can fail. Your backend should handle these
+ * error conditions appropriately.
+ *
+ * This function should not generate any bus I/O and should not block.
+ * If I/O is required (e.g. reading the active configuration value), it is
+ * OK to ignore these suggestions :)
+ *
+ * This function is executed when the user wishes to retrieve a list
+ * of USB devices connected to the system.
+ *
+ * Return 0 on success, or a LIBUSB_ERROR code on failure.
+ */
+ int (*get_device_list)(struct libusb_context *ctx,
+ struct discovered_devs **discdevs);
+
+ /* Open a device for I/O and other USB operations. The device handle
+ * is preallocated for you, you can retrieve the device in question
+ * through handle->dev.
+ *
+ * Your backend should allocate any internal resources required for I/O
+ * and other operations so that those operations can happen (hopefully)
+ * without hiccup. This is also a good place to inform libusb that it
+ * should monitor certain file descriptors related to this device -
+ * see the usbi_add_pollfd() function.
+ *
+ * This function should not generate any bus I/O and should not block.
+ *
+ * This function is called when the user attempts to obtain a device
+ * handle for a device.
+ *
+ * Return:
+ * - 0 on success
+ * - LIBUSB_ERROR_ACCESS if the user has insufficient permissions
+ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since
+ * discovery
+ * - another LIBUSB_ERROR code on other failure
+ *
+ * Do not worry about freeing the handle on failed open, the upper layers
+ * do this for you.
+ */
+ int (*open)(struct libusb_device_handle *handle);
+
+ /* Close a device such that the handle cannot be used again. Your backend
+ * should destroy any resources that were allocated in the open path.
+ * This may also be a good place to call usbi_remove_pollfd() to inform
+ * libusb of any file descriptors associated with this device that should
+ * no longer be monitored.
+ *
+ * This function is called when the user closes a device handle.
+ */
+ void (*close)(struct libusb_device_handle *handle);
+
+ /* Retrieve the device descriptor from a device.
+ *
+ * The descriptor should be retrieved from memory, NOT via bus I/O to the
+ * device. This means that you may have to cache it in a private structure
+ * during get_device_list enumeration. Alternatively, you may be able
+ * to retrieve it from a kernel interface (some Linux setups can do this)
+ * still without generating bus I/O.
+ *
+ * This function is expected to write DEVICE_DESC_LENGTH (18) bytes into
+ * buffer, which is guaranteed to be big enough.
+ *
+ * This function is called when sanity-checking a device before adding
+ * it to the list of discovered devices, and also when the user requests
+ * to read the device descriptor.
+ *
+ * This function is expected to return the descriptor in bus-endian format
+ * (LE). If it returns the multi-byte values in host-endian format,
+ * set the host_endian output parameter to "1".
+ *
+ * Return 0 on success or a LIBUSB_ERROR code on failure.
+ */
+ int (*get_device_descriptor)(struct libusb_device *device,
+ unsigned char *buffer, int *host_endian);
+
+ /* Get the ACTIVE configuration descriptor for a device.
+ *
+ * The descriptor should be retrieved from memory, NOT via bus I/O to the
+ * device. This means that you may have to cache it in a private structure
+ * during get_device_list enumeration. You may also have to keep track
+ * of which configuration is active when the user changes it.
+ *
+ * This function is expected to write len bytes of data into buffer, which
+ * is guaranteed to be big enough. If you can only do a partial write,
+ * return an error code.
+ *
+ * This function is expected to return the descriptor in bus-endian format
+ * (LE). If it returns the multi-byte values in host-endian format,
+ * set the host_endian output parameter to "1".
+ *
+ * Return:
+ * - 0 on success
+ * - LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state
+ * - another LIBUSB_ERROR code on other failure
+ */
+ int (*get_active_config_descriptor)(struct libusb_device *device,
+ unsigned char *buffer, size_t len, int *host_endian);
+
+ /* Get a specific configuration descriptor for a device.
+ *
+ * The descriptor should be retrieved from memory, NOT via bus I/O to the
+ * device. This means that you may have to cache it in a private structure
+ * during get_device_list enumeration.
+ *
+ * The requested descriptor is expressed as a zero-based index (i.e. 0
+ * indicates that we are requesting the first descriptor). The index does
+ * not (necessarily) equal the bConfigurationValue of the configuration
+ * being requested.
+ *
+ * This function is expected to write len bytes of data into buffer, which
+ * is guaranteed to be big enough. If you can only do a partial write,
+ * return an error code.
+ *
+ * This function is expected to return the descriptor in bus-endian format
+ * (LE). If it returns the multi-byte values in host-endian format,
+ * set the host_endian output parameter to "1".
+ *
+ * Return 0 on success or a LIBUSB_ERROR code on failure.
+ */
+ int (*get_config_descriptor)(struct libusb_device *device,
+ uint8_t config_index, unsigned char *buffer, size_t len,
+ int *host_endian);
+
+ /* Get the bConfigurationValue for the active configuration for a device.
+ * Optional. This should only be implemented if you can retrieve it from
+ * cache (don't generate I/O).
+ *
+ * If you cannot retrieve this from cache, either do not implement this
+ * function, or return LIBUSB_ERROR_NOT_SUPPORTED. This will cause
+ * libusb to retrieve the information through a standard control transfer.
+ *
+ * This function must be non-blocking.
+ * Return:
+ * - 0 on success
+ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+ * was opened
+ * - LIBUSB_ERROR_NOT_SUPPORTED if the value cannot be retrieved without
+ * blocking
+ * - another LIBUSB_ERROR code on other failure.
+ */
+ int (*get_configuration)(struct libusb_device_handle *handle, int *config);
+
+ /* Set the active configuration for a device.
+ *
+ * A configuration value of -1 should put the device in unconfigured state.
+ *
+ * This function can block.
+ *
+ * Return:
+ * - 0 on success
+ * - LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
+ * - LIBUSB_ERROR_BUSY if interfaces are currently claimed (and hence
+ * configuration cannot be changed)
+ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+ * was opened
+ * - another LIBUSB_ERROR code on other failure.
+ */
+ int (*set_configuration)(struct libusb_device_handle *handle, int config);
+
+ /* Claim an interface. When claimed, the application can then perform
+ * I/O to an interface's endpoints.
+ *
+ * This function should not generate any bus I/O and should not block.
+ * Interface claiming is a logical operation that simply ensures that
+ * no other drivers/applications are using the interface, and after
+ * claiming, no other drivers/applicatiosn can use the interface because
+ * we now "own" it.
+ *
+ * Return:
+ * - 0 on success
+ * - LIBUSB_ERROR_NOT_FOUND if the interface does not exist
+ * - LIBUSB_ERROR_BUSY if the interface is in use by another driver/app
+ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+ * was opened
+ * - another LIBUSB_ERROR code on other failure
+ */
+ int (*claim_interface)(struct libusb_device_handle *handle, int interface_number);
+
+ /* Release a previously claimed interface.
+ *
+ * This function should also generate a SET_INTERFACE control request,
+ * resetting the alternate setting of that interface to 0. It's OK for
+ * this function to block as a result.
+ *
+ * You will only ever be asked to release an interface which was
+ * successfully claimed earlier.
+ *
+ * Return:
+ * - 0 on success
+ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+ * was opened
+ * - another LIBUSB_ERROR code on other failure
+ */
+ int (*release_interface)(struct libusb_device_handle *handle, int interface_number);
+
+ /* Set the alternate setting for an interface.
+ *
+ * You will only ever be asked to set the alternate setting for an
+ * interface which was successfully claimed earlier.
+ *
+ * It's OK for this function to block.
+ *
+ * Return:
+ * - 0 on success
+ * - LIBUSB_ERROR_NOT_FOUND if the alternate setting does not exist
+ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+ * was opened
+ * - another LIBUSB_ERROR code on other failure
+ */
+ int (*set_interface_altsetting)(struct libusb_device_handle *handle,
+ int interface_number, int altsetting);
+
+ /* Clear a halt/stall condition on an endpoint.
+ *
+ * It's OK for this function to block.
+ *
+ * Return:
+ * - 0 on success
+ * - LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist
+ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+ * was opened
+ * - another LIBUSB_ERROR code on other failure
+ */
+ int (*clear_halt)(struct libusb_device_handle *handle,
+ unsigned char endpoint);
+
+ /* Perform a USB port reset to reinitialize a device.
+ *
+ * If possible, the handle should still be usable after the reset
+ * completes, assuming that the device descriptors did not change during
+ * reset and all previous interface state can be restored.
+ *
+ * If something changes, or you cannot easily locate/verify the resetted
+ * device, return LIBUSB_ERROR_NOT_FOUND. This prompts the application
+ * to close the old handle and re-enumerate the device.
+ *
+ * Return:
+ * - 0 on success
+ * - LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the device
+ * has been disconnected since it was opened
+ * - another LIBUSB_ERROR code on other failure
+ */
+ int (*reset_device)(struct libusb_device_handle *handle);
+
+ /* Determine if a kernel driver is active on an interface. Optional.
+ *
+ * The presence of a kernel driver on an interface indicates that any
+ * calls to claim_interface would fail with the LIBUSB_ERROR_BUSY code.
+ *
+ * Return:
+ * - 0 if no driver is active
+ * - 1 if a driver is active
+ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+ * was opened
+ * - another LIBUSB_ERROR code on other failure
+ */
+ int (*kernel_driver_active)(struct libusb_device_handle *handle,
+ int interface_number);
+
+ /* Detach a kernel driver from an interface. Optional.
+ *
+ * After detaching a kernel driver, the interface should be available
+ * for claim.
+ *
+ * Return:
+ * - 0 on success
+ * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active
+ * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist
+ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+ * was opened
+ * - another LIBUSB_ERROR code on other failure
+ */
+ int (*detach_kernel_driver)(struct libusb_device_handle *handle,
+ int interface_number);
+
+ /* Attach a kernel driver to an interface. Optional.
+ *
+ * Reattach a kernel driver to the device.
+ *
+ * Return:
+ * - 0 on success
+ * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active
+ * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist
+ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+ * was opened
+ * - LIBUSB_ERROR_BUSY if a program or driver has claimed the interface,
+ * preventing reattachment
+ * - another LIBUSB_ERROR code on other failure
+ */
+ int (*attach_kernel_driver)(struct libusb_device_handle *handle,
+ int interface_number);
+
+ /* Destroy a device. Optional.
+ *
+ * This function is called when the last reference to a device is
+ * destroyed. It should free any resources allocated in the get_device_list
+ * path.
+ */
+ void (*destroy_device)(struct libusb_device *dev);
+
+ /* Submit a transfer. Your implementation should take the transfer,
+ * morph it into whatever form your platform requires, and submit it
+ * asynchronously.
+ *
+ * This function must not block.
+ *
+ * Return:
+ * - 0 on success
+ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * - another LIBUSB_ERROR code on other failure
+ */
+ int (*submit_transfer)(struct usbi_transfer *itransfer);
+
+ /* Cancel a previously submitted transfer.
+ *
+ * This function must not block. The transfer cancellation must complete
+ * later, resulting in a call to usbi_handle_transfer_cancellation()
+ * from the context of handle_events.
+ */
+ int (*cancel_transfer)(struct usbi_transfer *itransfer);
+
+ /* Clear a transfer as if it has completed or cancelled, but do not
+ * report any completion/cancellation to the library. You should free
+ * all private data from the transfer as if you were just about to report
+ * completion or cancellation.
+ *
+ * This function might seem a bit out of place. It is used when libusb
+ * detects a disconnected device - it calls this function for all pending
+ * transfers before reporting completion (with the disconnect code) to
+ * the user. Maybe we can improve upon this internal interface in future.
+ */
+ void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
+
+ /* Handle any pending events. This involves monitoring any active
+ * transfers and processing their completion or cancellation.
+ *
+ * The function is passed an array of pollfd structures (size nfds)
+ * as a result of the poll() system call. The num_ready parameter
+ * indicates the number of file descriptors that have reported events
+ * (i.e. the poll() return value). This should be enough information
+ * for you to determine which actions need to be taken on the currently
+ * active transfers.
+ *
+ * For any cancelled transfers, call usbi_handle_transfer_cancellation().
+ * For completed transfers, call usbi_handle_transfer_completion().
+ * For control/bulk/interrupt transfers, populate the "transferred"
+ * element of the appropriate usbi_transfer structure before calling the
+ * above functions. For isochronous transfers, populate the status and
+ * transferred fields of the iso packet descriptors of the transfer.
+ *
+ * This function should also be able to detect disconnection of the
+ * device, reporting that situation with usbi_handle_disconnect().
+ *
+ * When processing an event related to a transfer, you probably want to
+ * take usbi_transfer.lock to prevent races. See the documentation for
+ * the usbi_transfer structure.
+ *
+ * Return 0 on success, or a LIBUSB_ERROR code on failure.
+ */
+ int (*handle_events)(struct libusb_context *ctx,
+ struct pollfd *fds, nfds_t nfds, int num_ready);
+
+ /* Get time from specified clock. At least two clocks must be implemented
+ by the backend: USBI_CLOCK_REALTIME, and USBI_CLOCK_MONOTONIC.
+
+ Description of clocks:
+ USBI_CLOCK_REALTIME : clock returns time since system epoch.
+ USBI_CLOCK_MONOTONIC: clock returns time since unspecified start
+ time (usually boot).
+ */
+ int (*clock_gettime)(int clkid, struct timespec *tp);
+
+#ifdef USBI_TIMERFD_AVAILABLE
+ /* clock ID of the clock that should be used for timerfd */
+ clockid_t (*get_timerfd_clockid)(void);
+#endif
+
+ /* Number of bytes to reserve for per-device private backend data.
+ * This private data area is accessible through the "os_priv" field of
+ * struct libusb_device. */
+ size_t device_priv_size;
+
+ /* Number of bytes to reserve for per-handle private backend data.
+ * This private data area is accessible through the "os_priv" field of
+ * struct libusb_device. */
+ size_t device_handle_priv_size;
+
+ /* Number of bytes to reserve for per-transfer private backend data.
+ * This private data area is accessible by calling
+ * usbi_transfer_get_os_priv() on the appropriate usbi_transfer instance.
+ */
+ size_t transfer_priv_size;
+
+ /* Mumber of additional bytes for os_priv for each iso packet.
+ * Can your backend use this? */
+ /* FIXME: linux can't use this any more. if other OS's cannot either,
+ * then remove this */
+ size_t add_iso_packet_size;
+};
+
+extern const struct usbi_os_backend * const usbi_backend;
+
+extern const struct usbi_os_backend linux_usbfs_backend;
+extern const struct usbi_os_backend darwin_backend;
+extern const struct usbi_os_backend windows_backend;
+
+#endif
+
diff --git a/libusb-1.0/libusb/os/.DS_Store b/libusb-1.0/libusb/os/.DS_Store
new file mode 100644
index 0000000..90333e8
--- /dev/null
+++ b/libusb-1.0/libusb/os/.DS_Store
Binary files differ
diff --git a/libusb-1.0/libusb/os/._.DS_Store b/libusb-1.0/libusb/os/._.DS_Store
new file mode 100644
index 0000000..338bd7b
--- /dev/null
+++ b/libusb-1.0/libusb/os/._.DS_Store
Binary files differ
diff --git a/libusb-1.0/libusb/os/darwin_usb.c b/libusb-1.0/libusb/os/darwin_usb.c
new file mode 100644
index 0000000..646c938
--- /dev/null
+++ b/libusb-1.0/libusb/os/darwin_usb.c
@@ -0,0 +1,1545 @@
+/*
+ * darwin backend for libusb 1.0
+ * Copyright (C) 2008-2010 Nathan Hjelm <hjelmn@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <mach/clock.h>
+#include <mach/clock_types.h>
+#include <mach/mach_host.h>
+
+#include <mach/mach_port.h>
+#include <IOKit/IOCFBundle.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOCFPlugIn.h>
+
+#include "darwin_usb.h"
+
+static mach_port_t libusb_darwin_mp = 0; /* master port */
+static CFRunLoopRef libusb_darwin_acfl = NULL; /* async cf loop */
+static int initCount = 0;
+
+/* async event thread */
+static pthread_t libusb_darwin_at;
+
+static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian);
+static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface);
+static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface);
+static int darwin_reset_device(struct libusb_device_handle *dev_handle);
+static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0);
+
+static const char *darwin_error_str (int result) {
+ switch (result) {
+ case kIOReturnSuccess:
+ return "no error";
+ case kIOReturnNotOpen:
+ return "device not opened for exclusive access";
+ case kIOReturnNoDevice:
+ return "no connection to an IOService";
+ case kIOUSBNoAsyncPortErr:
+ return "no async port has been opened for interface";
+ case kIOReturnExclusiveAccess:
+ return "another process has device opened for exclusive access";
+ case kIOUSBPipeStalled:
+ return "pipe is stalled";
+ case kIOReturnError:
+ return "could not establish a connection to the Darwin kernel";
+ case kIOUSBTransactionTimeout:
+ return "transaction timed out";
+ case kIOReturnBadArgument:
+ return "invalid argument";
+ case kIOReturnAborted:
+ return "transaction aborted";
+ case kIOReturnNotResponding:
+ return "device not responding";
+ case kIOReturnOverrun:
+ return "data overrun";
+ case kIOReturnCannotWire:
+ return "physical memory can not be wired down";
+ default:
+ return "unknown error";
+ }
+}
+
+static int darwin_to_libusb (int result) {
+ switch (result) {
+ case kIOReturnUnderrun:
+ case kIOReturnSuccess:
+ return LIBUSB_SUCCESS;
+ case kIOReturnNotOpen:
+ case kIOReturnNoDevice:
+ return LIBUSB_ERROR_NO_DEVICE;
+ case kIOReturnExclusiveAccess:
+ return LIBUSB_ERROR_ACCESS;
+ case kIOUSBPipeStalled:
+ return LIBUSB_ERROR_PIPE;
+ case kIOReturnBadArgument:
+ return LIBUSB_ERROR_INVALID_PARAM;
+ case kIOUSBTransactionTimeout:
+ return LIBUSB_ERROR_TIMEOUT;
+ case kIOReturnNotResponding:
+ case kIOReturnAborted:
+ case kIOReturnError:
+ case kIOUSBNoAsyncPortErr:
+ default:
+ return LIBUSB_ERROR_OTHER;
+ }
+}
+
+
+static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, uint8_t *pipep, uint8_t *ifcp) {
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+
+ /* current interface */
+ struct __darwin_interface *cInterface;
+
+ int8_t i, iface;
+
+ usbi_info (HANDLE_CTX(dev_handle), "converting ep address 0x%02x to pipeRef and interface", ep);
+
+ for (iface = 0 ; iface < USB_MAXINTERFACES ; iface++) {
+ cInterface = &priv->interfaces[iface];
+
+ if (dev_handle->claimed_interfaces & (1 << iface)) {
+ for (i = 0 ; i < cInterface->num_endpoints ; i++) {
+ if (cInterface->endpoint_addrs[i] == ep) {
+ *pipep = i + 1;
+ *ifcp = iface;
+ usbi_info (HANDLE_CTX(dev_handle), "pipe %d on interface %d matches", *pipep, *ifcp);
+ return 0;
+ }
+ }
+ }
+ }
+
+ /* No pipe found with the correct endpoint address */
+ usbi_warn (HANDLE_CTX(dev_handle), "no pipeRef found with endpoint address 0x%02x.", ep);
+
+ return -1;
+}
+
+static int usb_setup_device_iterator (io_iterator_t *deviceIterator) {
+ return IOServiceGetMatchingServices(libusb_darwin_mp, IOServiceMatching(kIOUSBDeviceClassName), deviceIterator);
+}
+
+static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp) {
+ io_cf_plugin_ref_t *plugInInterface = NULL;
+ usb_device_t **device;
+ io_service_t usbDevice;
+ long result;
+ SInt32 score;
+
+ if (!IOIteratorIsValid (deviceIterator))
+ return NULL;
+
+
+ while ((usbDevice = IOIteratorNext(deviceIterator))) {
+ result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID,
+ kIOCFPlugInInterfaceID, &plugInInterface,
+ &score);
+ if (kIOReturnSuccess == result && plugInInterface)
+ break;
+
+ usbi_dbg ("libusb/darwin.c usb_get_next_device: could not set up plugin for service: %s\n", darwin_error_str (result));
+ }
+
+ if (!usbDevice)
+ return NULL;
+
+ (void)IOObjectRelease(usbDevice);
+ (void)(*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID),
+ (LPVOID)&device);
+
+ (*plugInInterface)->Stop(plugInInterface);
+ IODestroyPlugInInterface (plugInInterface);
+
+ /* get the location from the device */
+ if (locationp)
+ (*(device))->GetLocationID(device, locationp);
+
+ return device;
+}
+
+static kern_return_t darwin_get_device (uint32_t dev_location, usb_device_t ***darwin_device) {
+ kern_return_t kresult;
+ UInt32 location;
+ io_iterator_t deviceIterator;
+
+ kresult = usb_setup_device_iterator (&deviceIterator);
+ if (kresult)
+ return kresult;
+
+ /* This port of libusb uses locations to keep track of devices. */
+ while ((*darwin_device = usb_get_next_device (deviceIterator, &location)) != NULL) {
+ if (location == dev_location)
+ break;
+
+ (**darwin_device)->Release(*darwin_device);
+ }
+
+ IOObjectRelease (deviceIterator);
+
+ if (!(*darwin_device))
+ return kIOReturnNoDevice;
+
+ return kIOReturnSuccess;
+}
+
+
+
+static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
+ struct libusb_context *ctx = (struct libusb_context *)ptr;
+ struct libusb_device_handle *handle;
+ struct darwin_device_priv *dpriv;
+ struct darwin_device_handle_priv *priv;
+
+ io_service_t device;
+ long location;
+ CFTypeRef locationCF;
+ UInt32 message;
+
+ usbi_info (ctx, "a device has been detached");
+
+ while ((device = IOIteratorNext (rem_devices)) != 0) {
+ /* get the location from the i/o registry */
+ locationCF = IORegistryEntryCreateCFProperty (device, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault, 0);
+
+ CFNumberGetValue(locationCF, kCFNumberLongType, &location);
+ CFRelease (locationCF);
+ IOObjectRelease (device);
+
+ usbi_mutex_lock(&ctx->open_devs_lock);
+ list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
+ dpriv = (struct darwin_device_priv *)handle->dev->os_priv;
+
+ /* the device may have been opened several times. write to each handle's event descriptor */
+ if (dpriv->location == location && handle->os_priv) {
+ priv = (struct darwin_device_handle_priv *)handle->os_priv;
+
+ message = MESSAGE_DEVICE_GONE;
+ write (priv->fds[1], &message, sizeof (message));
+ }
+ }
+
+ usbi_mutex_unlock(&ctx->open_devs_lock);
+ }
+}
+
+static void darwin_clear_iterator (io_iterator_t iter) {
+ io_service_t device;
+
+ while ((device = IOIteratorNext (iter)) != 0)
+ IOObjectRelease (device);
+}
+
+static void *event_thread_main (void *arg0) {
+ IOReturn kresult;
+ struct libusb_context *ctx = (struct libusb_context *)arg0;
+
+ /* hotplug (device removal) source */
+ CFRunLoopSourceRef libusb_notification_cfsource;
+ io_notification_port_t libusb_notification_port;
+ io_iterator_t libusb_rem_device_iterator;
+
+ usbi_info (ctx, "creating hotplug event source");
+
+ CFRetain (CFRunLoopGetCurrent ());
+
+ /* add the notification port to the run loop */
+ libusb_notification_port = IONotificationPortCreate (libusb_darwin_mp);
+ libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port);
+ CFRunLoopAddSource(CFRunLoopGetCurrent (), libusb_notification_cfsource, kCFRunLoopDefaultMode);
+
+ /* create notifications for removed devices */
+ kresult = IOServiceAddMatchingNotification (libusb_notification_port, kIOTerminatedNotification,
+ IOServiceMatching(kIOUSBDeviceClassName),
+ (IOServiceMatchingCallback)darwin_devices_detached,
+ (void *)ctx, &libusb_rem_device_iterator);
+
+ if (kresult != kIOReturnSuccess) {
+ usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult));
+
+ pthread_exit ((void *)kresult);
+ }
+
+ /* arm notifiers */
+ darwin_clear_iterator (libusb_rem_device_iterator);
+
+ /* let the main thread know about the async runloop */
+ libusb_darwin_acfl = CFRunLoopGetCurrent ();
+
+ usbi_info (ctx, "thread ready to receive events");
+
+ /* run the runloop */
+ CFRunLoopRun();
+
+ usbi_info (ctx, "thread exiting");
+
+ /* delete notification port */
+ CFRunLoopSourceInvalidate (libusb_notification_cfsource);
+ IONotificationPortDestroy (libusb_notification_port);
+
+ CFRelease (CFRunLoopGetCurrent ());
+
+ libusb_darwin_acfl = NULL;
+
+ pthread_exit (0);
+}
+
+static int darwin_init(struct libusb_context *ctx) {
+ IOReturn kresult;
+
+ if (!(initCount++)) {
+ /* Create the master port for talking to IOKit */
+ if (!libusb_darwin_mp) {
+ kresult = IOMasterPort (MACH_PORT_NULL, &libusb_darwin_mp);
+
+ if (kresult != kIOReturnSuccess || !libusb_darwin_mp)
+ return darwin_to_libusb (kresult);
+ }
+
+ pthread_create (&libusb_darwin_at, NULL, event_thread_main, (void *)ctx);
+
+ while (!libusb_darwin_acfl)
+ usleep (10);
+ }
+
+ return 0;
+}
+
+static void darwin_exit (void) {
+ if (!(--initCount)) {
+ void *ret;
+
+ /* stop the async runloop */
+ CFRunLoopStop (libusb_darwin_acfl);
+ pthread_join (libusb_darwin_at, &ret);
+
+ if (libusb_darwin_mp)
+ mach_port_deallocate(mach_task_self(), libusb_darwin_mp);
+
+ libusb_darwin_mp = 0;
+ }
+}
+
+static int darwin_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) {
+ struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
+
+ /* return cached copy */
+ memmove (buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH);
+
+ *host_endian = 0;
+
+ return 0;
+}
+
+static int get_configuration_index (struct libusb_device *dev, int config_value) {
+ struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
+ UInt8 i, numConfig;
+ IOUSBConfigurationDescriptorPtr desc;
+ IOReturn kresult;
+
+ /* is there a simpler way to determine the index? */
+ kresult = (*(priv->device))->GetNumberOfConfigurations (priv->device, &numConfig);
+ if (kresult != kIOReturnSuccess)
+ return darwin_to_libusb (kresult);
+
+ for (i = 0 ; i < numConfig ; i++) {
+ (*(priv->device))->GetConfigurationDescriptorPtr (priv->device, i, &desc);
+
+ if (desc->bConfigurationValue == config_value)
+ return i;
+ }
+
+ /* configuration not found */
+ return LIBUSB_ERROR_OTHER;
+}
+
+static int darwin_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) {
+ struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
+ int config_index;
+
+ if (0 == priv->active_config)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ config_index = get_configuration_index (dev, priv->active_config);
+ if (config_index < 0)
+ return config_index;
+
+ return darwin_get_config_descriptor (dev, config_index, buffer, len, host_endian);
+}
+
+static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) {
+ struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
+ IOUSBConfigurationDescriptorPtr desc;
+ IOReturn kresult;
+ usb_device_t **device = NULL;
+
+ if (!priv)
+ return LIBUSB_ERROR_OTHER;
+
+ if (!priv->device) {
+ kresult = darwin_get_device (priv->location, &device);
+ if (kresult || !device) {
+ usbi_err (DEVICE_CTX (dev), "could not find device: %s", darwin_error_str (kresult));
+
+ return darwin_to_libusb (kresult);
+ }
+
+ /* don't have to open the device to get a config descriptor */
+ } else
+ device = priv->device;
+
+ kresult = (*device)->GetConfigurationDescriptorPtr (device, config_index, &desc);
+ if (kresult == kIOReturnSuccess) {
+ /* copy descriptor */
+ if (libusb_le16_to_cpu(desc->wTotalLength) < len)
+ len = libusb_le16_to_cpu(desc->wTotalLength);
+
+ memmove (buffer, desc, len);
+
+ /* GetConfigurationDescriptorPtr returns the descriptor in USB bus order */
+ *host_endian = 0;
+ }
+
+ if (!priv->device)
+ (*device)->Release (device);
+
+ return darwin_to_libusb (kresult);
+}
+
+/* check whether the os has configured the device */
+static int darwin_check_configuration (struct libusb_context *ctx, struct libusb_device *dev, usb_device_t **darwin_device) {
+ struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
+
+ IOUSBConfigurationDescriptorPtr configDesc;
+ IOUSBFindInterfaceRequest request;
+ kern_return_t kresult;
+ io_iterator_t interface_iterator;
+ io_service_t firstInterface;
+
+ if (priv->dev_descriptor.bNumConfigurations < 1) {
+ usbi_err (ctx, "device has no configurations");
+ return LIBUSB_ERROR_OTHER; /* no configurations at this speed so we can't use it */
+ }
+
+ /* find the first configuration */
+ kresult = (*darwin_device)->GetConfigurationDescriptorPtr (darwin_device, 0, &configDesc);
+ priv->first_config = (kIOReturnSuccess == kresult) ? configDesc->bConfigurationValue : 1;
+
+ /* check if the device is already configured. there is probably a better way than iterating over the
+ to accomplish this (the trick is we need to avoid a call to GetConfigurations since buggy devices
+ might lock up on the device request) */
+
+ /* Setup the Interface Request */
+ request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+ request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+ kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator);
+ if (kresult)
+ return darwin_to_libusb (kresult);
+
+ /* iterate once */
+ firstInterface = IOIteratorNext(interface_iterator);
+
+ /* done with the interface iterator */
+ IOObjectRelease(interface_iterator);
+
+ if (firstInterface) {
+ IOObjectRelease (firstInterface);
+
+ /* device is configured */
+ if (priv->dev_descriptor.bNumConfigurations == 1)
+ /* to avoid problems with some devices get the configurations value from the configuration descriptor */
+ priv->active_config = priv->first_config;
+ else
+ /* devices with more than one configuration should work with GetConfiguration */
+ (*darwin_device)->GetConfiguration (darwin_device, &priv->active_config);
+ } else
+ /* not configured */
+ priv->active_config = 0;
+
+ usbi_info (ctx, "active config: %u, first config: %u", priv->active_config, priv->first_config);
+
+ return 0;
+}
+
+static int process_new_device (struct libusb_context *ctx, usb_device_t **device, UInt32 locationID, struct discovered_devs **_discdevs) {
+ struct darwin_device_priv *priv;
+ struct libusb_device *dev;
+ struct discovered_devs *discdevs;
+ UInt16 address, idVendor, idProduct;
+ UInt8 bDeviceClass, bDeviceSubClass;
+ IOUSBDevRequest req;
+ int ret = 0, need_unref = 0;
+
+ do {
+ dev = usbi_get_device_by_session_id(ctx, locationID);
+ if (!dev) {
+ usbi_info (ctx, "allocating new device for location 0x%08x", locationID);
+ dev = usbi_alloc_device(ctx, locationID);
+ need_unref = 1;
+ } else
+ usbi_info (ctx, "using existing device for location 0x%08x", locationID);
+
+ if (!dev) {
+ ret = LIBUSB_ERROR_NO_MEM;
+ break;
+ }
+
+ priv = (struct darwin_device_priv *)dev->os_priv;
+
+ /* Set up request for device descriptor */
+ req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ req.bRequest = kUSBRqGetDescriptor;
+ req.wValue = kUSBDeviceDesc << 8;
+ req.wIndex = 0;
+ req.wLength = sizeof(IOUSBDeviceDescriptor);
+ req.pData = &(priv->dev_descriptor);
+
+ (*(device))->GetDeviceAddress (device, (USBDeviceAddress *)&address);
+ (*(device))->GetDeviceProduct (device, &idProduct);
+ (*(device))->GetDeviceVendor (device, &idVendor);
+ (*(device))->GetDeviceClass (device, &bDeviceClass);
+ (*(device))->GetDeviceSubClass (device, &bDeviceSubClass);
+
+ /**** retrieve device descriptors ****/
+ /* according to Apple's documentation the device must be open for DeviceRequest but we may not be able to open some
+ * devices and Apple's USB Prober doesn't bother to open the device before issuing a descriptor request */
+ ret = (*(device))->DeviceRequest (device, &req);
+ if (ret != kIOReturnSuccess) {
+ int try_unsuspend = 1;
+#if DeviceVersion >= 320
+ UInt32 info;
+
+ /* device may be suspended. unsuspend it and try again */
+ /* IOUSBFamily 320+ provides a way to detect device suspension but earlier versions do not */
+ (void)(*device)->GetUSBDeviceInformation (device, &info);
+
+ try_unsuspend = info & (1 << kUSBInformationDeviceIsSuspendedBit);
+#endif
+
+ /* the device should be open before to device is unsuspended */
+ (void) (*device)->USBDeviceOpenSeize(device);
+
+ if (try_unsuspend) {
+ /* resume the device */
+ (void)(*device)->USBDeviceSuspend (device, 0);
+
+ ret = (*(device))->DeviceRequest (device, &req);
+
+ /* resuspend the device */
+ (void)(*device)->USBDeviceSuspend (device, 1);
+ }
+
+ (*device)->USBDeviceClose (device);
+ }
+
+ if (ret != kIOReturnSuccess) {
+ usbi_warn (ctx, "could not retrieve device descriptor: %s. skipping device", darwin_error_str (ret));
+ ret = -1;
+ break;
+ }
+
+ /**** end: retrieve device descriptors ****/
+
+ /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices. */
+ if (libusb_le16_to_cpu (priv->dev_descriptor.idProduct) != idProduct) {
+ /* not a valid device */
+ usbi_warn (ctx, "idProduct from iokit (%04x) does not match idProduct in descriptor (%04x). skipping device",
+ idProduct, libusb_le16_to_cpu (priv->dev_descriptor.idProduct));
+ ret = -1;
+ break;
+ }
+
+ dev->bus_number = locationID >> 24;
+ dev->device_address = address;
+
+ /* check current active configuration (and cache the first configuration value-- which may be used by claim_interface) */
+ ret = darwin_check_configuration (ctx, dev, device);
+ if (ret < 0)
+ break;
+
+ /* save our location, we'll need this later */
+ priv->location = locationID;
+ snprintf(priv->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", address, idVendor, idProduct, bDeviceClass, bDeviceSubClass);
+
+ ret = usbi_sanitize_device (dev);
+ if (ret < 0)
+ break;
+
+ /* append the device to the list of discovered devices */
+ discdevs = discovered_devs_append(*_discdevs, dev);
+ if (!discdevs) {
+ ret = LIBUSB_ERROR_NO_MEM;
+ break;
+ }
+
+ *_discdevs = discdevs;
+
+ usbi_info (ctx, "found device with address %d at %s", dev->device_address, priv->sys_path);
+ } while (0);
+
+ if (need_unref)
+ libusb_unref_device(dev);
+
+ return ret;
+}
+
+static int darwin_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) {
+ io_iterator_t deviceIterator;
+ usb_device_t **device;
+ kern_return_t kresult;
+ UInt32 location;
+
+ if (!libusb_darwin_mp)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ kresult = usb_setup_device_iterator (&deviceIterator);
+ if (kresult != kIOReturnSuccess)
+ return darwin_to_libusb (kresult);
+
+ while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
+ (void) process_new_device (ctx, device, location, _discdevs);
+
+ (*(device))->Release(device);
+ }
+
+ IOObjectRelease(deviceIterator);
+
+ return 0;
+}
+
+static int darwin_open (struct libusb_device_handle *dev_handle) {
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+ struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+ usb_device_t **darwin_device;
+ IOReturn kresult;
+
+ if (0 == dpriv->open_count) {
+ kresult = darwin_get_device (dpriv->location, &darwin_device);
+ if (kresult) {
+ usbi_err (HANDLE_CTX (dev_handle), "could not find device: %s", darwin_error_str (kresult));
+ return darwin_to_libusb (kresult);
+ }
+
+ dpriv->device = darwin_device;
+
+ /* try to open the device */
+ kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device);
+
+ if (kresult != kIOReturnSuccess) {
+ usbi_err (HANDLE_CTX (dev_handle), "USBDeviceOpen: %s", darwin_error_str(kresult));
+
+ switch (kresult) {
+ case kIOReturnExclusiveAccess:
+ /* it is possible to perform some actions on a device that is not open so do not return an error */
+ priv->is_open = 0;
+
+ break;
+ default:
+ (*(dpriv->device))->Release (dpriv->device);
+ dpriv->device = NULL;
+ return darwin_to_libusb (kresult);
+ }
+ } else {
+ priv->is_open = 1;
+
+ /* create async event source */
+ kresult = (*(dpriv->device))->CreateDeviceAsyncEventSource (dpriv->device, &priv->cfSource);
+
+ CFRetain (libusb_darwin_acfl);
+
+ /* add the cfSource to the aync run loop */
+ CFRunLoopAddSource(libusb_darwin_acfl, priv->cfSource, kCFRunLoopCommonModes);
+ }
+ }
+
+ /* device opened successfully */
+ dpriv->open_count++;
+
+ /* create a file descriptor for notifications */
+ pipe (priv->fds);
+
+ /* set the pipe to be non-blocking */
+ fcntl (priv->fds[1], F_SETFD, O_NONBLOCK);
+
+ usbi_add_pollfd(HANDLE_CTX(dev_handle), priv->fds[0], POLLIN);
+
+ usbi_info (HANDLE_CTX (dev_handle), "device open for access");
+
+ return 0;
+}
+
+static void darwin_close (struct libusb_device_handle *dev_handle) {
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+ struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+ IOReturn kresult;
+ int i;
+
+ if (dpriv->open_count == 0) {
+ /* something is probably very wrong if this is the case */
+ usbi_err (HANDLE_CTX (dev_handle), "Close called on a device that was not open!\n");
+ return;
+ }
+
+ dpriv->open_count--;
+
+ /* make sure all interfaces are released */
+ for (i = 0 ; i < USB_MAXINTERFACES ; i++)
+ if (dev_handle->claimed_interfaces & (1 << i))
+ libusb_release_interface (dev_handle, i);
+
+ if (0 == dpriv->open_count) {
+ if (priv->is_open) {
+ /* delete the device's async event source */
+ if (priv->cfSource) {
+ CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode);
+ CFRelease (priv->cfSource);
+ }
+
+ /* close the device */
+ kresult = (*(dpriv->device))->USBDeviceClose(dpriv->device);
+ if (kresult) {
+ /* Log the fact that we had a problem closing the file, however failing a
+ * close isn't really an error, so return success anyway */
+ usbi_err (HANDLE_CTX (dev_handle), "USBDeviceClose: %s", darwin_error_str(kresult));
+ }
+ }
+
+ kresult = (*(dpriv->device))->Release(dpriv->device);
+ if (kresult) {
+ /* Log the fact that we had a problem closing the file, however failing a
+ * close isn't really an error, so return success anyway */
+ usbi_err (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult));
+ }
+
+ dpriv->device = NULL;
+ }
+
+ /* file descriptors are maintained per-instance */
+ usbi_remove_pollfd (HANDLE_CTX (dev_handle), priv->fds[0]);
+ close (priv->fds[1]);
+ close (priv->fds[0]);
+
+ priv->fds[0] = priv->fds[1] = -1;
+}
+
+static int darwin_get_configuration(struct libusb_device_handle *dev_handle, int *config) {
+ struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+
+ *config = (int) dpriv->active_config;
+
+ return 0;
+}
+
+static int darwin_set_configuration(struct libusb_device_handle *dev_handle, int config) {
+ struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+ IOReturn kresult;
+ int i;
+
+ /* Setting configuration will invalidate the interface, so we need
+ to reclaim it. First, dispose of existing interfaces, if any. */
+ for (i = 0 ; i < USB_MAXINTERFACES ; i++)
+ if (dev_handle->claimed_interfaces & (1 << i))
+ darwin_release_interface (dev_handle, i);
+
+ kresult = (*(dpriv->device))->SetConfiguration (dpriv->device, config);
+ if (kresult != kIOReturnSuccess)
+ return darwin_to_libusb (kresult);
+
+ /* Reclaim any interfaces. */
+ for (i = 0 ; i < USB_MAXINTERFACES ; i++)
+ if (dev_handle->claimed_interfaces & (1 << i))
+ darwin_claim_interface (dev_handle, i);
+
+ dpriv->active_config = config;
+
+ return 0;
+}
+
+static int darwin_get_interface (usb_device_t **darwin_device, uint8_t ifc, io_service_t *usbInterfacep) {
+ IOUSBFindInterfaceRequest request;
+ uint8_t current_interface;
+ kern_return_t kresult;
+ io_iterator_t interface_iterator;
+
+ *usbInterfacep = IO_OBJECT_NULL;
+
+ /* Setup the Interface Request */
+ request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+ request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+ kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator);
+ if (kresult)
+ return kresult;
+
+ for ( current_interface = 0 ; current_interface <= ifc ; current_interface++ ) {
+ *usbInterfacep = IOIteratorNext(interface_iterator);
+ if (current_interface != ifc)
+ (void) IOObjectRelease (*usbInterfacep);
+ }
+
+ /* done with the interface iterator */
+ IOObjectRelease(interface_iterator);
+
+ return 0;
+}
+
+static int get_endpoints (struct libusb_device_handle *dev_handle, int iface) {
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+
+ /* current interface */
+ struct __darwin_interface *cInterface = &priv->interfaces[iface];
+
+ kern_return_t kresult;
+
+ u_int8_t numep, direction, number;
+ u_int8_t dont_care1, dont_care3;
+ u_int16_t dont_care2;
+ int i;
+
+ usbi_info (HANDLE_CTX (dev_handle), "building table of endpoints.");
+
+ /* retrieve the total number of endpoints on this interface */
+ kresult = (*(cInterface->interface))->GetNumEndpoints(cInterface->interface, &numep);
+ if (kresult) {
+ usbi_err (HANDLE_CTX (dev_handle), "can't get number of endpoints for interface: %s", darwin_error_str(kresult));
+ return darwin_to_libusb (kresult);
+ }
+
+ /* iterate through pipe references */
+ for (i = 1 ; i <= numep ; i++) {
+ kresult = (*(cInterface->interface))->GetPipeProperties(cInterface->interface, i, &direction, &number, &dont_care1,
+ &dont_care2, &dont_care3);
+
+ if (kresult != kIOReturnSuccess) {
+ usbi_err (HANDLE_CTX (dev_handle), "error getting pipe information for pipe %d: %s", i, darwin_error_str(kresult));
+
+ return darwin_to_libusb (kresult);
+ }
+
+ usbi_info (HANDLE_CTX (dev_handle), "interface: %i pipe %i: dir: %i number: %i", iface, i, direction, number);
+
+ cInterface->endpoint_addrs[i - 1] = ((direction << 7 & LIBUSB_ENDPOINT_DIR_MASK) | (number & LIBUSB_ENDPOINT_ADDRESS_MASK));
+ }
+
+ cInterface->num_endpoints = numep;
+
+ return 0;
+}
+
+static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface) {
+ struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+ io_service_t usbInterface = IO_OBJECT_NULL;
+ IOReturn kresult;
+ IOCFPlugInInterface **plugInInterface = NULL;
+ SInt32 score;
+
+ /* current interface */
+ struct __darwin_interface *cInterface = &priv->interfaces[iface];
+
+ kresult = darwin_get_interface (dpriv->device, iface, &usbInterface);
+ if (kresult != kIOReturnSuccess)
+ return darwin_to_libusb (kresult);
+
+ /* make sure we have an interface */
+ if (!usbInterface && dpriv->first_config != 0) {
+ usbi_info (HANDLE_CTX (dev_handle), "no interface found; setting configuration: %d", dpriv->first_config);
+
+ /* set the configuration */
+ kresult = darwin_set_configuration (dev_handle, dpriv->first_config);
+ if (kresult != LIBUSB_SUCCESS) {
+ usbi_err (HANDLE_CTX (dev_handle), "could not set configuration");
+ return kresult;
+ }
+
+ kresult = darwin_get_interface (dpriv->device, iface, &usbInterface);
+ if (kresult) {
+ usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult));
+ return darwin_to_libusb (kresult);
+ }
+ }
+
+ if (!usbInterface) {
+ usbi_err (HANDLE_CTX (dev_handle), "interface not found");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ /* get an interface to the device's interface */
+ kresult = IOCreatePlugInInterfaceForService (usbInterface, kIOUSBInterfaceUserClientTypeID,
+ kIOCFPlugInInterfaceID, &plugInInterface, &score);
+ if (kresult) {
+ usbi_err (HANDLE_CTX (dev_handle), "IOCreatePlugInInterfaceForService: %s", darwin_error_str(kresult));
+ return darwin_to_libusb (kresult);
+ }
+
+ if (!plugInInterface) {
+ usbi_err (HANDLE_CTX (dev_handle), "plugin interface not found");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ /* ignore release error */
+ (void)IOObjectRelease (usbInterface);
+
+ /* Do the actual claim */
+ kresult = (*plugInInterface)->QueryInterface(plugInInterface,
+ CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
+ (LPVOID)&cInterface->interface);
+ if (kresult || !cInterface->interface) {
+ usbi_err (HANDLE_CTX (dev_handle), "QueryInterface: %s", darwin_error_str(kresult));
+ return darwin_to_libusb (kresult);
+ }
+
+ /* We no longer need the intermediate plug-in */
+ (*plugInInterface)->Release(plugInInterface);
+
+ /* claim the interface */
+ kresult = (*(cInterface->interface))->USBInterfaceOpen(cInterface->interface);
+ if (kresult) {
+ usbi_err (HANDLE_CTX (dev_handle), "USBInterfaceOpen: %s", darwin_error_str(kresult));
+ return darwin_to_libusb (kresult);
+ }
+
+ /* update list of endpoints */
+ kresult = get_endpoints (dev_handle, iface);
+ if (kresult) {
+ /* this should not happen */
+ darwin_release_interface (dev_handle, iface);
+ usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table");
+ return kresult;
+ }
+
+ cInterface->cfSource = NULL;
+
+ /* create async event source */
+ kresult = (*(cInterface->interface))->CreateInterfaceAsyncEventSource (cInterface->interface, &cInterface->cfSource);
+ if (kresult != kIOReturnSuccess) {
+ usbi_err (HANDLE_CTX (dev_handle), "could not create async event source");
+
+ /* can't continue without an async event source */
+ (void)darwin_release_interface (dev_handle, iface);
+
+ return darwin_to_libusb (kresult);
+ }
+
+ /* add the cfSource to the async thread's run loop */
+ CFRunLoopAddSource(libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode);
+
+ usbi_info (HANDLE_CTX (dev_handle), "interface opened");
+
+ return 0;
+}
+
+static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface) {
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+ IOReturn kresult;
+
+ /* current interface */
+ struct __darwin_interface *cInterface = &priv->interfaces[iface];
+
+ /* Check to see if an interface is open */
+ if (!cInterface->interface)
+ return LIBUSB_SUCCESS;
+
+ /* clean up endpoint data */
+ cInterface->num_endpoints = 0;
+
+ /* delete the interface's async event source */
+ if (cInterface->cfSource) {
+ CFRunLoopRemoveSource (libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode);
+ CFRelease (cInterface->cfSource);
+ }
+
+ kresult = (*(cInterface->interface))->USBInterfaceClose(cInterface->interface);
+ if (kresult)
+ usbi_err (HANDLE_CTX (dev_handle), "USBInterfaceClose: %s", darwin_error_str(kresult));
+
+ kresult = (*(cInterface->interface))->Release(cInterface->interface);
+ if (kresult != kIOReturnSuccess)
+ usbi_err (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult));
+
+ cInterface->interface = IO_OBJECT_NULL;
+
+ return darwin_to_libusb (kresult);
+}
+
+static int darwin_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) {
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+ IOReturn kresult;
+
+ /* current interface */
+ struct __darwin_interface *cInterface = &priv->interfaces[iface];
+
+ if (!cInterface->interface)
+ return LIBUSB_ERROR_NO_DEVICE;
+
+ kresult = (*(cInterface->interface))->SetAlternateInterface (cInterface->interface, altsetting);
+ if (kresult != kIOReturnSuccess)
+ darwin_reset_device (dev_handle);
+
+ /* update list of endpoints */
+ kresult = get_endpoints (dev_handle, iface);
+ if (kresult) {
+ /* this should not happen */
+ darwin_release_interface (dev_handle, iface);
+ usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table");
+ return kresult;
+ }
+
+ return darwin_to_libusb (kresult);
+}
+
+static int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) {
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+
+ /* current interface */
+ struct __darwin_interface *cInterface;
+ uint8_t pipeRef, iface;
+ IOReturn kresult;
+
+ /* determine the interface/endpoint to use */
+ if (ep_to_pipeRef (dev_handle, endpoint, &pipeRef, &iface) != 0) {
+ usbi_err (HANDLE_CTX (dev_handle), "endpoint not found on any open interface");
+
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ cInterface = &priv->interfaces[iface];
+
+#if (InterfaceVersion < 190)
+ kresult = (*(cInterface->interface))->ClearPipeStall(cInterface->interface, pipeRef);
+#else
+ /* newer versions of darwin support clearing additional bits on the device's endpoint */
+ kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef);
+#endif
+ if (kresult)
+ usbi_err (HANDLE_CTX (dev_handle), "ClearPipeStall: %s", darwin_error_str (kresult));
+
+ return darwin_to_libusb (kresult);
+}
+
+static int darwin_reset_device(struct libusb_device_handle *dev_handle) {
+ struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+ IOReturn kresult;
+
+ kresult = (*(dpriv->device))->ResetDevice (dpriv->device);
+ if (kresult)
+ usbi_err (HANDLE_CTX (dev_handle), "ResetDevice: %s", darwin_error_str (kresult));
+
+ return darwin_to_libusb (kresult);
+}
+
+static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, int interface) {
+ struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+ io_service_t usbInterface;
+ CFTypeRef driver;
+ IOReturn kresult;
+
+ kresult = darwin_get_interface (dpriv->device, interface, &usbInterface);
+ if (kresult) {
+ usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult));
+
+ return darwin_to_libusb (kresult);
+ }
+
+ driver = IORegistryEntryCreateCFProperty (usbInterface, kIOBundleIdentifierKey, kCFAllocatorDefault, 0);
+ IOObjectRelease (usbInterface);
+
+ if (driver) {
+ CFRelease (driver);
+
+ return 1;
+ }
+
+ /* no driver */
+ return 0;
+}
+
+/* attaching/detaching kernel drivers is not currently supported (maybe in the future?) */
+static int darwin_attach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+static void darwin_destroy_device(struct libusb_device *dev) {
+}
+
+static int submit_bulk_transfer(struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
+
+ IOReturn ret;
+ uint8_t is_read; /* 0 = we're reading, 1 = we're writing */
+ uint8_t transferType;
+ /* None of the values below are used in libusb for bulk transfers */
+ uint8_t direction, number, interval, pipeRef, iface;
+ uint16_t maxPacketSize;
+
+ struct __darwin_interface *cInterface;
+
+ /* are we reading or writing? */
+ is_read = transfer->endpoint & LIBUSB_ENDPOINT_IN;
+
+ if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
+ usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
+
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ cInterface = &priv->interfaces[iface];
+
+ (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
+ &transferType, &maxPacketSize, &interval);
+
+ /* submit the request */
+ /* timeouts are unavailable on interrupt endpoints */
+ if (transferType == kUSBInterrupt) {
+ if (is_read)
+ ret = (*(cInterface->interface))->ReadPipeAsync(cInterface->interface, pipeRef, transfer->buffer,
+ transfer->length, darwin_async_io_callback, itransfer);
+ else
+ ret = (*(cInterface->interface))->WritePipeAsync(cInterface->interface, pipeRef, transfer->buffer,
+ transfer->length, darwin_async_io_callback, itransfer);
+ } else {
+ if (is_read)
+ ret = (*(cInterface->interface))->ReadPipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer,
+ transfer->length, transfer->timeout, transfer->timeout,
+ darwin_async_io_callback, (void *)itransfer);
+ else
+ ret = (*(cInterface->interface))->WritePipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer,
+ transfer->length, transfer->timeout, transfer->timeout,
+ darwin_async_io_callback, (void *)itransfer);
+ }
+
+ if (ret)
+ usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", is_read ? "In" : "Out",
+ darwin_error_str(ret), ret);
+
+ return darwin_to_libusb (ret);
+}
+
+static int submit_iso_transfer(struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
+
+ IOReturn kresult;
+ uint8_t is_read; /* 0 = we're writing, 1 = we're reading */
+ uint8_t pipeRef, iface;
+ UInt64 frame;
+ AbsoluteTime atTime;
+ int i;
+
+ struct __darwin_interface *cInterface;
+
+ /* are we reading or writing? */
+ is_read = transfer->endpoint & LIBUSB_ENDPOINT_IN;
+
+ /* construct an array of IOUSBIsocFrames */
+ tpriv->isoc_framelist = (IOUSBIsocFrame*) calloc (transfer->num_iso_packets, sizeof(IOUSBIsocFrame));
+ if (!tpriv->isoc_framelist)
+ return LIBUSB_ERROR_NO_MEM;
+
+ /* copy the frame list from the libusb descriptor (the structures differ only is member order) */
+ for (i = 0 ; i < transfer->num_iso_packets ; i++)
+ tpriv->isoc_framelist[i].frReqCount = transfer->iso_packet_desc[i].length;
+
+ /* determine the interface/endpoint to use */
+ if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
+ usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
+
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ cInterface = &priv->interfaces[iface];
+
+ /* Last but not least we need the bus frame number */
+ kresult = (*(cInterface->interface))->GetBusFrameNumber(cInterface->interface, &frame, &atTime);
+ if (kresult) {
+ usbi_err (TRANSFER_CTX (transfer), "failed to get bus frame number: %d", kresult);
+ free(tpriv->isoc_framelist);
+ tpriv->isoc_framelist = NULL;
+
+ return darwin_to_libusb (kresult);
+ }
+
+ /* schedule for a frame a little in the future */
+ frame += 2;
+
+ /* submit the request */
+ if (is_read)
+ kresult = (*(cInterface->interface))->ReadIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame,
+ transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback,
+ itransfer);
+ else
+ kresult = (*(cInterface->interface))->WriteIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame,
+ transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback,
+ itransfer);
+
+ if (kresult != kIOReturnSuccess) {
+ usbi_err (TRANSFER_CTX (transfer), "isochronous transfer failed (dir: %s): %s", is_read ? "In" : "Out",
+ darwin_error_str(kresult));
+ free (tpriv->isoc_framelist);
+ tpriv->isoc_framelist = NULL;
+ }
+
+ return darwin_to_libusb (kresult);
+}
+
+static int submit_control_transfer(struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_control_setup *setup = (struct libusb_control_setup *) transfer->buffer;
+ struct darwin_device_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv;
+ struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+
+ IOReturn kresult;
+
+ bzero(&tpriv->req, sizeof(tpriv->req));
+
+ /* IOUSBDeviceInterface expects the request in cpu endianess */
+ tpriv->req.bmRequestType = setup->bmRequestType;
+ tpriv->req.bRequest = setup->bRequest;
+ /* these values should be in bus order from libusb_fill_control_setup */
+ tpriv->req.wValue = OSSwapLittleToHostInt16 (setup->wValue);
+ tpriv->req.wIndex = OSSwapLittleToHostInt16 (setup->wIndex);
+ tpriv->req.wLength = OSSwapLittleToHostInt16 (setup->wLength);
+ /* data is stored after the libusb control block */
+ tpriv->req.pData = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
+ tpriv->req.completionTimeout = transfer->timeout;
+ tpriv->req.noDataTimeout = transfer->timeout;
+
+ /* all transfers in libusb-1.0 are async */
+ kresult = (*(dpriv->device))->DeviceRequestAsyncTO(dpriv->device, &(tpriv->req), darwin_async_io_callback, itransfer);
+
+ if (kresult != kIOReturnSuccess)
+ usbi_err (TRANSFER_CTX (transfer), "control request failed: %s", darwin_error_str(kresult));
+
+ return darwin_to_libusb (kresult);
+}
+
+static int darwin_submit_transfer(struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ return submit_control_transfer(itransfer);
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ return submit_bulk_transfer(itransfer);
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ return submit_iso_transfer(itransfer);
+ default:
+ usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+}
+
+static int cancel_control_transfer(struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct darwin_device_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv;
+ IOReturn kresult;
+
+ usbi_info (ITRANSFER_CTX (itransfer), "WARNING: aborting all transactions control pipe");
+
+ kresult = (*(dpriv->device))->USBDeviceAbortPipeZero (dpriv->device);
+
+ return darwin_to_libusb (kresult);
+}
+
+static int darwin_abort_transfers (struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
+ struct __darwin_interface *cInterface;
+ uint8_t pipeRef, iface;
+ IOReturn kresult;
+
+ if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
+ usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
+
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ cInterface = &priv->interfaces[iface];
+
+ usbi_info (ITRANSFER_CTX (itransfer), "WARNING: aborting all transactions on interface %d pipe %d", iface, pipeRef);
+
+ /* abort transactions */
+ (*(cInterface->interface))->AbortPipe (cInterface->interface, pipeRef);
+
+ usbi_info (ITRANSFER_CTX (itransfer), "calling clear pipe stall to clear the data toggle bit");
+
+ /* clear the data toggle bit */
+#if (InterfaceVersion < 190)
+ kresult = (*(cInterface->interface))->ClearPipeStall(cInterface->interface, pipeRef);
+#else
+ /* newer versions of darwin support clearing additional bits on the device's endpoint */
+ kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef);
+#endif
+
+ return darwin_to_libusb (kresult);
+}
+
+static int darwin_cancel_transfer(struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ return cancel_control_transfer(itransfer);
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ return darwin_abort_transfers (itransfer);
+ default:
+ usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+}
+
+static void darwin_clear_transfer_priv (struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+
+ if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS && tpriv->isoc_framelist) {
+ free (tpriv->isoc_framelist);
+ tpriv->isoc_framelist = NULL;
+ }
+}
+
+static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0) {
+ struct usbi_transfer *itransfer = (struct usbi_transfer *)refcon;
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
+ UInt32 message;
+
+ usbi_info (ITRANSFER_CTX (itransfer), "an async io operation has completed");
+
+ /* send a completion message to the device's file descriptor */
+ message = MESSAGE_ASYNC_IO_COMPLETE;
+ write (priv->fds[1], &message, sizeof (message));
+ write (priv->fds[1], &itransfer, sizeof (itransfer));
+ write (priv->fds[1], &result, sizeof (IOReturn));
+ write (priv->fds[1], &arg0, sizeof (UInt32));
+}
+
+static int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_t result) {
+ switch (result) {
+ case kIOReturnUnderrun:
+ case kIOReturnSuccess:
+ return LIBUSB_TRANSFER_COMPLETED;
+ case kIOReturnAborted:
+ return LIBUSB_TRANSFER_CANCELLED;
+ case kIOUSBPipeStalled:
+ usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: pipe is stalled");
+ return LIBUSB_TRANSFER_STALL;
+ case kIOReturnOverrun:
+ usbi_err (ITRANSFER_CTX (itransfer), "transfer error: data overrun");
+ return LIBUSB_TRANSFER_OVERFLOW;
+ case kIOUSBTransactionTimeout:
+ usbi_err (ITRANSFER_CTX (itransfer), "transfer error: timed out");
+ return LIBUSB_TRANSFER_TIMED_OUT;
+ default:
+ usbi_err (ITRANSFER_CTX (itransfer), "transfer error: %s (value = 0x%08x)", darwin_error_str (result), result);
+ return LIBUSB_TRANSFER_ERROR;
+ }
+}
+
+static void darwin_handle_callback (struct usbi_transfer *itransfer, kern_return_t result, UInt32 io_size) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+ int isIsoc = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type;
+ int isBulk = LIBUSB_TRANSFER_TYPE_BULK == transfer->type;
+ int isControl = LIBUSB_TRANSFER_TYPE_CONTROL == transfer->type;
+ int isInterrupt = LIBUSB_TRANSFER_TYPE_INTERRUPT == transfer->type;
+ int i;
+
+ if (!isIsoc && !isBulk && !isControl && !isInterrupt) {
+ usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
+ return;
+ }
+
+ usbi_info (ITRANSFER_CTX (itransfer), "handling %s completion with kernel status %d",
+ isControl ? "control" : isBulk ? "bulk" : isIsoc ? "isoc" : "interrupt", result);
+
+ if (kIOReturnSuccess == result || kIOReturnUnderrun == result) {
+ if (isIsoc && tpriv->isoc_framelist) {
+ /* copy isochronous results back */
+
+ for (i = 0; i < transfer->num_iso_packets ; i++) {
+ struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i];
+ lib_desc->status = darwin_to_libusb (tpriv->isoc_framelist[i].frStatus);
+ lib_desc->actual_length = tpriv->isoc_framelist[i].frActCount;
+ }
+ } else if (!isIsoc)
+ itransfer->transferred += io_size;
+ }
+
+ /* it is ok to handle cancelled transfers without calling usbi_handle_transfer_cancellation (we catch timeout transfers) */
+ usbi_handle_transfer_completion (itransfer, darwin_transfer_status (itransfer, result));
+}
+
+static int op_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds_t nfds, int num_ready) {
+ struct usbi_transfer *itransfer;
+ UInt32 io_size;
+ IOReturn kresult;
+ int i = 0, ret;
+ UInt32 message;
+
+ usbi_mutex_lock(&ctx->open_devs_lock);
+ for (i = 0; i < nfds && num_ready > 0; i++) {
+ struct pollfd *pollfd = &fds[i];
+ struct libusb_device_handle *handle;
+ struct darwin_device_handle_priv *hpriv = NULL;
+
+ usbi_info (ctx, "checking fd %i with revents = %x", fds[i], pollfd->revents);
+
+ if (!pollfd->revents)
+ continue;
+
+ num_ready--;
+ list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
+ hpriv = (struct darwin_device_handle_priv *)handle->os_priv;
+ if (hpriv->fds[0] == pollfd->fd)
+ break;
+ }
+
+ if (!(pollfd->revents & POLLERR)) {
+ ret = read (hpriv->fds[0], &message, sizeof (message));
+ if (ret < sizeof (message))
+ continue;
+ } else
+ /* could not poll the device-- response is to delete the device (this seems a little heavy-handed) */
+ message = MESSAGE_DEVICE_GONE;
+
+ switch (message) {
+ case MESSAGE_DEVICE_GONE:
+ /* remove the device's async port from the runloop */
+ if (hpriv->cfSource) {
+ if (libusb_darwin_acfl)
+ CFRunLoopRemoveSource (libusb_darwin_acfl, hpriv->cfSource, kCFRunLoopDefaultMode);
+ CFRelease (hpriv->cfSource);
+ hpriv->cfSource = NULL;
+ }
+
+ usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fds[0]);
+ usbi_handle_disconnect(handle);
+
+ /* done with this device */
+ continue;
+ case MESSAGE_ASYNC_IO_COMPLETE:
+ read (hpriv->fds[0], &itransfer, sizeof (itransfer));
+ read (hpriv->fds[0], &kresult, sizeof (IOReturn));
+ read (hpriv->fds[0], &io_size, sizeof (UInt32));
+
+ darwin_handle_callback (itransfer, kresult, io_size);
+ break;
+ default:
+ usbi_err (ctx, "unknown message received from device pipe");
+ }
+ }
+
+ usbi_mutex_unlock(&ctx->open_devs_lock);
+
+ return 0;
+}
+
+static int darwin_clock_gettime(int clk_id, struct timespec *tp) {
+ mach_timespec_t sys_time;
+ clock_serv_t clock_ref;
+
+ switch (clk_id) {
+ case USBI_CLOCK_REALTIME:
+ /* CLOCK_REALTIME represents time since the epoch */
+ host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clock_ref);
+ break;
+ case USBI_CLOCK_MONOTONIC:
+ /* use system boot time as reference for the monotonic clock */
+ host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clock_ref);
+ break;
+ default:
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ clock_get_time (clock_ref, &sys_time);
+
+ tp->tv_sec = sys_time.tv_sec;
+ tp->tv_nsec = sys_time.tv_nsec;
+
+ return 0;
+}
+
+const struct usbi_os_backend darwin_backend = {
+ .name = "Darwin",
+ .init = darwin_init,
+ .exit = darwin_exit,
+ .get_device_list = darwin_get_device_list,
+ .get_device_descriptor = darwin_get_device_descriptor,
+ .get_active_config_descriptor = darwin_get_active_config_descriptor,
+ .get_config_descriptor = darwin_get_config_descriptor,
+
+ .open = darwin_open,
+ .close = darwin_close,
+ .get_configuration = darwin_get_configuration,
+ .set_configuration = darwin_set_configuration,
+ .claim_interface = darwin_claim_interface,
+ .release_interface = darwin_release_interface,
+
+ .set_interface_altsetting = darwin_set_interface_altsetting,
+ .clear_halt = darwin_clear_halt,
+ .reset_device = darwin_reset_device,
+
+ .kernel_driver_active = darwin_kernel_driver_active,
+ .detach_kernel_driver = darwin_detach_kernel_driver,
+ .attach_kernel_driver = darwin_attach_kernel_driver,
+
+ .destroy_device = darwin_destroy_device,
+
+ .submit_transfer = darwin_submit_transfer,
+ .cancel_transfer = darwin_cancel_transfer,
+ .clear_transfer_priv = darwin_clear_transfer_priv,
+
+ .handle_events = op_handle_events,
+
+ .clock_gettime = darwin_clock_gettime,
+
+ .device_priv_size = sizeof(struct darwin_device_priv),
+ .device_handle_priv_size = sizeof(struct darwin_device_handle_priv),
+ .transfer_priv_size = sizeof(struct darwin_transfer_priv),
+ .add_iso_packet_size = 0,
+};
+
diff --git a/libusb-1.0/libusb/os/darwin_usb.h b/libusb-1.0/libusb/os/darwin_usb.h
new file mode 100644
index 0000000..a71d464
--- /dev/null
+++ b/libusb-1.0/libusb/os/darwin_usb.h
@@ -0,0 +1,167 @@
+/*
+ * darwin backend for libusb 1.0
+ * Copyright (C) 2008-2009 Nathan Hjelm <hjelmn@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if !defined(LIBUSB_DARWIN_H)
+#define LIBUSB_DARWIN_H
+
+#include "libusbi.h"
+
+#include <IOKit/IOTypes.h>
+#include <IOKit/IOCFBundle.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOCFPlugIn.h>
+
+/* IOUSBInterfaceInferface */
+#if defined (kIOUSBInterfaceInterfaceID300)
+
+#define usb_interface_t IOUSBInterfaceInterface300
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300
+#define InterfaceVersion 300
+
+#elif defined (kIOUSBInterfaceInterfaceID245)
+
+#define usb_interface_t IOUSBInterfaceInterface245
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245
+#define InterfaceVersion 245
+
+#elif defined (kIOUSBInterfaceInterfaceID220)
+
+#define usb_interface_t IOUSBInterfaceInterface220
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
+#define InterfaceVersion 220
+
+#elif defined (kIOUSBInterfaceInterfaceID197)
+
+#define usb_interface_t IOUSBInterfaceInterface197
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197
+#define InterfaceVersion 197
+
+#elif defined (kIOUSBInterfaceInterfaceID190)
+
+#define usb_interface_t IOUSBInterfaceInterface190
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190
+#define InterfaceVersion 190
+
+#elif defined (kIOUSBInterfaceInterfaceID182)
+
+#define usb_interface_t IOUSBInterfaceInterface182
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182
+#define InterfaceVersion 182
+
+#else
+
+#error "IOUSBFamily is too old. Please upgrade your OS"
+
+#endif
+
+/* IOUSBDeviceInterface */
+#if defined (kIOUSBDeviceInterfaceID320)
+
+#define usb_device_t IOUSBDeviceInterface320
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID320
+#define DeviceVersion 320
+
+#elif defined (kIOUSBDeviceInterfaceID300)
+
+#define usb_device_t IOUSBDeviceInterface300
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID300
+#define DeviceVersion 300
+
+#elif defined (kIOUSBDeviceInterfaceID245)
+
+#define usb_device_t IOUSBDeviceInterface245
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID245
+#define DeviceVersion 245
+
+#elif defined (kIOUSBDeviceInterfaceID197)
+
+#define usb_device_t IOUSBDeviceInterface197
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
+#define DeviceVersion 197
+
+#elif defined (kIOUSBDeviceInterfaceID187)
+
+#define usb_device_t IOUSBDeviceInterface187
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID187
+#define DeviceVersion 187
+
+#elif defined (kIOUSBDeviceInterfaceID182)
+
+#define usb_device_t IOUSBDeviceInterface182
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID182
+#define DeviceVersion 182
+
+#else
+
+#error "IOUSBFamily is too old. Please upgrade your OS"
+
+#endif
+
+#if !defined(IO_OBJECT_NULL)
+#define IO_OBJECT_NULL ((io_object_t) 0)
+#endif
+
+typedef IOCFPlugInInterface *io_cf_plugin_ref_t;
+typedef IONotificationPortRef io_notification_port_t;
+
+/* private structures */
+struct darwin_device_priv {
+ IOUSBDeviceDescriptor dev_descriptor;
+ UInt32 location;
+ char sys_path[21];
+ usb_device_t **device;
+ int open_count;
+ UInt8 first_config, active_config;
+};
+
+struct darwin_device_handle_priv {
+ int is_open;
+ CFRunLoopSourceRef cfSource;
+ int fds[2];
+
+ struct __darwin_interface {
+ usb_interface_t **interface;
+ uint8_t num_endpoints;
+ CFRunLoopSourceRef cfSource;
+ uint8_t endpoint_addrs[USB_MAXENDPOINTS];
+ } interfaces[USB_MAXINTERFACES];
+};
+
+struct darwin_transfer_priv {
+ /* Isoc */
+ IOUSBIsocFrame *isoc_framelist;
+
+ /* Control */
+#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
+ IOUSBDevRequestTO req;
+#else
+ IOUSBDevRequest req;
+#endif
+
+ /* Bulk */
+};
+
+enum {
+ MESSAGE_DEVICE_GONE,
+ MESSAGE_ASYNC_IO_COMPLETE
+};
+
+
+
+#endif
diff --git a/libusb-1.0/libusb/os/linux_usbfs.c b/libusb-1.0/libusb/os/linux_usbfs.c
new file mode 100644
index 0000000..5c2a6e8
--- /dev/null
+++ b/libusb-1.0/libusb/os/linux_usbfs.c
@@ -0,0 +1,2220 @@
+/*
+ * Linux usbfs backend for libusb
+ * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include "libusb.h"
+#include "libusbi.h"
+#include "linux_usbfs.h"
+
+/* sysfs vs usbfs:
+ * opening a usbfs node causes the device to be resumed, so we attempt to
+ * avoid this during enumeration.
+ *
+ * sysfs allows us to read the kernel's in-memory copies of device descriptors
+ * and so forth, avoiding the need to open the device:
+ * - The binary "descriptors" file was added in 2.6.23.
+ * - The "busnum" file was added in 2.6.22
+ * - The "devnum" file has been present since pre-2.6.18
+ * - the "bConfigurationValue" file has been present since pre-2.6.18
+ *
+ * If we have bConfigurationValue, busnum, and devnum, then we can determine
+ * the active configuration without having to open the usbfs node in RDWR mode.
+ * We assume this is the case if we see the busnum file (indicates 2.6.22+).
+ * The busnum file is important as that is the only way we can relate sysfs
+ * devices to usbfs nodes.
+ *
+ * If we also have descriptors, we can obtain the device descriptor and active
+ * configuration without touching usbfs at all.
+ *
+ * The descriptors file originally only contained the active configuration
+ * descriptor alongside the device descriptor, but all configurations are
+ * included as of Linux 2.6.26.
+ */
+
+/* endianness for multi-byte fields:
+ *
+ * Descriptors exposed by usbfs have the multi-byte fields in the device
+ * descriptor as host endian. Multi-byte fields in the other descriptors are
+ * bus-endian. The kernel documentation says otherwise, but it is wrong.
+ */
+
+static const char *usbfs_path = NULL;
+
+/* Linux 2.6.32 adds support for a bulk continuation URB flag. this basically
+ * allows us to mark URBs as being part of a specific logical transfer when
+ * we submit them to the kernel. then, on any error error except a
+ * cancellation, all URBs within that transfer will be cancelled with the
+ * endpoint is disabled, meaning that no more data can creep in during the
+ * time it takes to cancel the remaining URBs.
+ *
+ * The BULK_CONTINUATION flag must be set on all URBs within a bulk transfer
+ * (in either direction) except the first.
+ * For IN transfers, we must also set SHORT_NOT_OK on all the URBs.
+ * For OUT transfers, SHORT_NOT_OK must not be set. The effective behaviour
+ * (where an OUT transfer does not complete, the rest of the URBs in the
+ * transfer get cancelled) is already in effect, and setting this flag is
+ * disallowed (a kernel with USB debugging enabled will reject such URBs).
+ */
+static int supports_flag_bulk_continuation = -1;
+
+/* clock ID for monotonic clock, as not all clock sources are available on all
+ * systems. appropriate choice made at initialization time. */
+static clockid_t monotonic_clkid = -1;
+
+/* do we have a busnum to relate devices? this also implies that we can read
+ * the active configuration through bConfigurationValue */
+static int sysfs_can_relate_devices = -1;
+
+/* do we have a descriptors file? */
+static int sysfs_has_descriptors = -1;
+
+struct linux_device_priv {
+ char *sysfs_dir;
+ unsigned char *dev_descriptor;
+ unsigned char *config_descriptor;
+};
+
+struct linux_device_handle_priv {
+ int fd;
+};
+
+enum reap_action {
+ NORMAL = 0,
+ /* submission failed after the first URB, so await cancellation/completion
+ * of all the others */
+ SUBMIT_FAILED,
+
+ /* cancelled by user or timeout */
+ CANCELLED,
+
+ /* completed multi-URB transfer in non-final URB */
+ COMPLETED_EARLY,
+
+ /* one or more urbs encountered a low-level error */
+ ERROR,
+};
+
+struct linux_transfer_priv {
+ union {
+ struct usbfs_urb *urbs;
+ struct usbfs_urb **iso_urbs;
+ };
+
+ enum reap_action reap_action;
+ int num_urbs;
+ unsigned int num_retired;
+ enum libusb_transfer_status reap_status;
+
+ /* next iso packet in user-supplied transfer to be populated */
+ int iso_packet_offset;
+};
+
+static void __get_usbfs_path(struct libusb_device *dev, char *path)
+{
+ snprintf(path, PATH_MAX, "%s/%03d/%03d", usbfs_path, dev->bus_number,
+ dev->device_address);
+}
+
+static struct linux_device_priv *__device_priv(struct libusb_device *dev)
+{
+ return (struct linux_device_priv *) dev->os_priv;
+}
+
+static struct linux_device_handle_priv *__device_handle_priv(
+ struct libusb_device_handle *handle)
+{
+ return (struct linux_device_handle_priv *) handle->os_priv;
+}
+
+static int check_usb_vfs(const char *dirname)
+{
+ DIR *dir;
+ struct dirent *entry;
+ int found = 0;
+
+ dir = opendir(dirname);
+ if (!dir)
+ return 0;
+
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_name[0] == '.')
+ continue;
+
+ /* We assume if we find any files that it must be the right place */
+ found = 1;
+ break;
+ }
+
+ closedir(dir);
+ return found;
+}
+
+static const char *find_usbfs_path(void)
+{
+ const char *path = "/dev/bus/usb";
+ const char *ret = NULL;
+
+ if (check_usb_vfs(path)) {
+ ret = path;
+ } else {
+ path = "/proc/bus/usb";
+ if (check_usb_vfs(path))
+ ret = path;
+ }
+
+ usbi_dbg("found usbfs at %s", ret);
+ return ret;
+}
+
+/* the monotonic clock is not usable on all systems (e.g. embedded ones often
+ * seem to lack it). fall back to REALTIME if we have to. */
+static clockid_t find_monotonic_clock(void)
+{
+ struct timespec ts;
+ int r;
+
+#ifdef CLOCK_MONOTONIC
+ /* Linux 2.6.28 adds CLOCK_MONOTONIC_RAW but we don't use it
+ * because it's not available through timerfd */
+ r = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (r == 0)
+ return CLOCK_MONOTONIC;
+ usbi_dbg("monotonic clock doesn't work, errno %d", errno);
+#endif
+
+ return CLOCK_REALTIME;
+}
+
+/* bulk continuation URB flag available from Linux 2.6.32 */
+static int check_flag_bulk_continuation(void)
+{
+ struct utsname uts;
+ int sublevel;
+
+ if (uname(&uts) < 0)
+ return -1;
+ if (strlen(uts.release) < 4)
+ return 0;
+ if (strncmp(uts.release, "2.6.", 4) != 0)
+ return 0;
+
+ sublevel = atoi(uts.release + 4);
+ return sublevel >= 32;
+}
+
+static int op_init(struct libusb_context *ctx)
+{
+ struct stat statbuf;
+ int r;
+
+ usbfs_path = find_usbfs_path();
+ if (!usbfs_path) {
+ usbi_err(ctx, "could not find usbfs");
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ if (monotonic_clkid == -1)
+ monotonic_clkid = find_monotonic_clock();
+
+ if (supports_flag_bulk_continuation == -1) {
+ supports_flag_bulk_continuation = check_flag_bulk_continuation();
+ if (supports_flag_bulk_continuation == -1) {
+ usbi_err(ctx, "error checking for bulk continuation support");
+ return LIBUSB_ERROR_OTHER;
+ }
+ }
+
+ if (supports_flag_bulk_continuation)
+ usbi_dbg("bulk continuation flag supported");
+
+ r = stat(SYSFS_DEVICE_PATH, &statbuf);
+ if (r == 0 && S_ISDIR(statbuf.st_mode)) {
+ usbi_dbg("found usb devices in sysfs");
+ } else {
+ usbi_dbg("sysfs usb info not available");
+ sysfs_has_descriptors = 0;
+ sysfs_can_relate_devices = 0;
+ }
+
+ return 0;
+}
+
+static int usbfs_get_device_descriptor(struct libusb_device *dev,
+ unsigned char *buffer)
+{
+ struct linux_device_priv *priv = __device_priv(dev);
+
+ /* return cached copy */
+ memcpy(buffer, priv->dev_descriptor, DEVICE_DESC_LENGTH);
+ return 0;
+}
+
+static int __open_sysfs_attr(struct libusb_device *dev, const char *attr)
+{
+ struct linux_device_priv *priv = __device_priv(dev);
+ char filename[PATH_MAX];
+ int fd;
+
+ snprintf(filename, PATH_MAX, "%s/%s/%s",
+ SYSFS_DEVICE_PATH, priv->sysfs_dir, attr);
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ usbi_err(DEVICE_CTX(dev),
+ "open %s failed ret=%d errno=%d", filename, fd, errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ return fd;
+}
+
+static int sysfs_get_device_descriptor(struct libusb_device *dev,
+ unsigned char *buffer)
+{
+ int fd;
+ ssize_t r;
+
+ /* sysfs provides access to an in-memory copy of the device descriptor,
+ * so we use that rather than keeping our own copy */
+
+ fd = __open_sysfs_attr(dev, "descriptors");
+ if (fd < 0)
+ return fd;
+
+ r = read(fd, buffer, DEVICE_DESC_LENGTH);;
+ close(fd);
+ if (r < 0) {
+ usbi_err(DEVICE_CTX(dev), "read failed, ret=%d errno=%d", fd, errno);
+ return LIBUSB_ERROR_IO;
+ } else if (r < DEVICE_DESC_LENGTH) {
+ usbi_err(DEVICE_CTX(dev), "short read %d/%d", r, DEVICE_DESC_LENGTH);
+ return LIBUSB_ERROR_IO;
+ }
+
+ return 0;
+}
+
+static int op_get_device_descriptor(struct libusb_device *dev,
+ unsigned char *buffer, int *host_endian)
+{
+ if (sysfs_has_descriptors) {
+ return sysfs_get_device_descriptor(dev, buffer);
+ } else {
+ *host_endian = 1;
+ return usbfs_get_device_descriptor(dev, buffer);
+ }
+}
+
+static int usbfs_get_active_config_descriptor(struct libusb_device *dev,
+ unsigned char *buffer, size_t len)
+{
+ struct linux_device_priv *priv = __device_priv(dev);
+ if (!priv->config_descriptor)
+ return LIBUSB_ERROR_NOT_FOUND; /* device is unconfigured */
+
+ /* retrieve cached copy */
+ memcpy(buffer, priv->config_descriptor, len);
+ return 0;
+}
+
+/* read the bConfigurationValue for a device */
+static int sysfs_get_active_config(struct libusb_device *dev, int *config)
+{
+ char *endptr;
+ char tmp[4] = {0, 0, 0, 0};
+ long num;
+ int fd;
+ size_t r;
+
+ fd = __open_sysfs_attr(dev, "bConfigurationValue");
+ if (fd < 0)
+ return fd;
+
+ r = read(fd, tmp, sizeof(tmp));
+ close(fd);
+ if (r < 0) {
+ usbi_err(DEVICE_CTX(dev),
+ "read bConfigurationValue failed ret=%d errno=%d", r, errno);
+ return LIBUSB_ERROR_IO;
+ } else if (r == 0) {
+ usbi_err(DEVICE_CTX(dev), "device unconfigured");
+ *config = -1;
+ return 0;
+ }
+
+ if (tmp[sizeof(tmp) - 1] != 0) {
+ usbi_err(DEVICE_CTX(dev), "not null-terminated?");
+ return LIBUSB_ERROR_IO;
+ } else if (tmp[0] == 0) {
+ usbi_err(DEVICE_CTX(dev), "no configuration value?");
+ return LIBUSB_ERROR_IO;
+ }
+
+ num = strtol(tmp, &endptr, 10);
+ if (endptr == tmp) {
+ usbi_err(DEVICE_CTX(dev), "error converting '%s' to integer", tmp);
+ return LIBUSB_ERROR_IO;
+ }
+
+ *config = (int) num;
+ return 0;
+}
+
+/* takes a usbfs/descriptors fd seeked to the start of a configuration, and
+ * seeks to the next one. */
+static int seek_to_next_config(struct libusb_context *ctx, int fd,
+ int host_endian)
+{
+ struct libusb_config_descriptor config;
+ unsigned char tmp[6];
+ off_t off;
+ int r;
+
+ /* read first 6 bytes of descriptor */
+ r = read(fd, tmp, sizeof(tmp));
+ if (r < 0) {
+ usbi_err(ctx, "read failed ret=%d errno=%d", r, errno);
+ return LIBUSB_ERROR_IO;
+ } else if (r < sizeof(tmp)) {
+ usbi_err(ctx, "short descriptor read %d/%d", r, sizeof(tmp));
+ return LIBUSB_ERROR_IO;
+ }
+
+ /* seek forward to end of config */
+ usbi_parse_descriptor(tmp, "bbwbb", &config, host_endian);
+ off = lseek(fd, config.wTotalLength - sizeof(tmp), SEEK_CUR);
+ if (off < 0) {
+ usbi_err(ctx, "seek failed ret=%d errno=%d", off, errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ return 0;
+}
+
+static int sysfs_get_active_config_descriptor(struct libusb_device *dev,
+ unsigned char *buffer, size_t len)
+{
+ int fd;
+ ssize_t r;
+ off_t off;
+ int to_copy;
+ int config;
+ unsigned char tmp[6];
+
+ r = sysfs_get_active_config(dev, &config);
+ if (r < 0)
+ return r;
+ if (config == -1)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ usbi_dbg("active configuration %d", config);
+
+ /* sysfs provides access to an in-memory copy of the device descriptor,
+ * so we use that rather than keeping our own copy */
+
+ fd = __open_sysfs_attr(dev, "descriptors");
+ if (fd < 0)
+ return fd;
+
+ /* device might have been unconfigured since we read bConfigurationValue,
+ * so first check that there is any config descriptor data at all... */
+ off = lseek(fd, 0, SEEK_END);
+ if (off < 1) {
+ usbi_err(DEVICE_CTX(dev), "end seek failed, ret=%d errno=%d",
+ off, errno);
+ close(fd);
+ return LIBUSB_ERROR_IO;
+ } else if (off == DEVICE_DESC_LENGTH) {
+ close(fd);
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ off = lseek(fd, DEVICE_DESC_LENGTH, SEEK_SET);
+ if (off < 0) {
+ usbi_err(DEVICE_CTX(dev), "seek failed, ret=%d errno=%d", off, errno);
+ close(fd);
+ return LIBUSB_ERROR_IO;
+ }
+
+ /* unbounded loop: we expect the descriptor to be present under all
+ * circumstances */
+ while (1) {
+ r = read(fd, tmp, sizeof(tmp));
+ if (r < 0) {
+ usbi_err(DEVICE_CTX(dev), "read failed, ret=%d errno=%d",
+ fd, errno);
+ return LIBUSB_ERROR_IO;
+ } else if (r < sizeof(tmp)) {
+ usbi_err(DEVICE_CTX(dev), "short read %d/%d", r, sizeof(tmp));
+ return LIBUSB_ERROR_IO;
+ }
+
+ /* check bConfigurationValue */
+ if (tmp[5] == config)
+ break;
+
+ /* try the next descriptor */
+ off = lseek(fd, 0 - sizeof(tmp), SEEK_CUR);
+ if (off < 0)
+ return LIBUSB_ERROR_IO;
+
+ r = seek_to_next_config(DEVICE_CTX(dev), fd, 0);
+ if (r < 0)
+ return r;
+ }
+
+ to_copy = (len < sizeof(tmp)) ? len : sizeof(tmp);
+ memcpy(buffer, tmp, to_copy);
+ if (len > sizeof(tmp)) {
+ r = read(fd, buffer + sizeof(tmp), len - sizeof(tmp));
+ if (r < 0) {
+ usbi_err(DEVICE_CTX(dev), "read failed, ret=%d errno=%d",
+ fd, errno);
+ r = LIBUSB_ERROR_IO;
+ } else if (r == 0) {
+ usbi_dbg("device is unconfigured");
+ r = LIBUSB_ERROR_NOT_FOUND;
+ } else if (r < len - sizeof(tmp)) {
+ usbi_err(DEVICE_CTX(dev), "short read %d/%d", r, len);
+ r = LIBUSB_ERROR_IO;
+ }
+ } else {
+ r = 0;
+ }
+
+ close(fd);
+ return r;
+}
+
+static int op_get_active_config_descriptor(struct libusb_device *dev,
+ unsigned char *buffer, size_t len, int *host_endian)
+{
+ if (sysfs_has_descriptors) {
+ return sysfs_get_active_config_descriptor(dev, buffer, len);
+ } else {
+ return usbfs_get_active_config_descriptor(dev, buffer, len);
+ }
+}
+
+/* takes a usbfs fd, attempts to find the requested config and copy a certain
+ * amount of it into an output buffer. */
+static int get_config_descriptor(struct libusb_context *ctx, int fd,
+ uint8_t config_index, unsigned char *buffer, size_t len)
+{
+ off_t off;
+ ssize_t r;
+
+ off = lseek(fd, DEVICE_DESC_LENGTH, SEEK_SET);
+ if (off < 0) {
+ usbi_err(ctx, "seek failed ret=%d errno=%d", off, errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ /* might need to skip some configuration descriptors to reach the
+ * requested configuration */
+ while (config_index > 0) {
+ r = seek_to_next_config(ctx, fd, 1);
+ if (r < 0)
+ return r;
+ config_index--;
+ }
+
+ /* read the rest of the descriptor */
+ r = read(fd, buffer, len);
+ if (r < 0) {
+ usbi_err(ctx, "read failed ret=%d errno=%d", r, errno);
+ return LIBUSB_ERROR_IO;
+ } else if (r < len) {
+ usbi_err(ctx, "short output read %d/%d", r, len);
+ return LIBUSB_ERROR_IO;
+ }
+
+ return 0;
+}
+
+static int op_get_config_descriptor(struct libusb_device *dev,
+ uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
+{
+ char filename[PATH_MAX];
+ int fd;
+ int r;
+
+ /* always read from usbfs: sysfs only has the active descriptor
+ * this will involve waking the device up, but oh well! */
+
+ /* FIXME: the above is no longer true, new kernels have all descriptors
+ * in the descriptors file. but its kinda hard to detect if the kernel
+ * is sufficiently new. */
+
+ __get_usbfs_path(dev, filename);
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ usbi_err(DEVICE_CTX(dev),
+ "open '%s' failed, ret=%d errno=%d", filename, fd, errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ r = get_config_descriptor(DEVICE_CTX(dev), fd, config_index, buffer, len);
+ close(fd);
+ return r;
+}
+
+/* cache the active config descriptor in memory. a value of -1 means that
+ * we aren't sure which one is active, so just assume the first one.
+ * only for usbfs. */
+static int cache_active_config(struct libusb_device *dev, int fd,
+ int active_config)
+{
+ struct linux_device_priv *priv = __device_priv(dev);
+ struct libusb_config_descriptor config;
+ unsigned char tmp[8];
+ unsigned char *buf;
+ int idx;
+ int r;
+
+ if (active_config == -1) {
+ idx = 0;
+ } else {
+ r = usbi_get_config_index_by_value(dev, active_config, &idx);
+ if (r < 0)
+ return r;
+ if (idx == -1)
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ r = get_config_descriptor(DEVICE_CTX(dev), fd, idx, tmp, sizeof(tmp));
+ if (r < 0) {
+ usbi_err(DEVICE_CTX(dev), "first read error %d", r);
+ return r;
+ }
+
+ usbi_parse_descriptor(tmp, "bbw", &config, 0);
+ buf = malloc(config.wTotalLength);
+ if (!buf)
+ return LIBUSB_ERROR_NO_MEM;
+
+ r = get_config_descriptor(DEVICE_CTX(dev), fd, idx, buf,
+ config.wTotalLength);
+ if (r < 0) {
+ free(buf);
+ return r;
+ }
+
+ if (priv->config_descriptor)
+ free(priv->config_descriptor);
+ priv->config_descriptor = buf;
+ return 0;
+}
+
+/* send a control message to retrieve active configuration */
+static int usbfs_get_active_config(struct libusb_device *dev, int fd)
+{
+ unsigned char active_config = 0;
+ int r;
+
+ struct usbfs_ctrltransfer ctrl = {
+ .bmRequestType = LIBUSB_ENDPOINT_IN,
+ .bRequest = LIBUSB_REQUEST_GET_CONFIGURATION,
+ .wValue = 0,
+ .wIndex = 0,
+ .wLength = 1,
+ .timeout = 1000,
+ .data = &active_config
+ };
+
+ r = ioctl(fd, IOCTL_USBFS_CONTROL, &ctrl);
+ if (r < 0) {
+ if (errno == ENODEV)
+ return LIBUSB_ERROR_NO_DEVICE;
+
+ /* we hit this error path frequently with buggy devices :( */
+ usbi_warn(DEVICE_CTX(dev),
+ "get_configuration failed ret=%d errno=%d", r, errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ return active_config;
+}
+
+static int initialize_device(struct libusb_device *dev, uint8_t busnum,
+ uint8_t devaddr, const char *sysfs_dir)
+{
+ struct linux_device_priv *priv = __device_priv(dev);
+ unsigned char *dev_buf;
+ char path[PATH_MAX];
+ int fd;
+ int active_config = 0;
+ int device_configured = 1;
+ ssize_t r;
+
+ dev->bus_number = busnum;
+ dev->device_address = devaddr;
+
+ if (sysfs_dir) {
+ priv->sysfs_dir = malloc(strlen(sysfs_dir) + 1);
+ if (!priv->sysfs_dir)
+ return LIBUSB_ERROR_NO_MEM;
+ strcpy(priv->sysfs_dir, sysfs_dir);
+ }
+
+ if (sysfs_has_descriptors)
+ return 0;
+
+ /* cache device descriptor in memory so that we can retrieve it later
+ * without waking the device up (op_get_device_descriptor) */
+
+ priv->dev_descriptor = NULL;
+ priv->config_descriptor = NULL;
+
+ if (sysfs_can_relate_devices) {
+ int tmp = sysfs_get_active_config(dev, &active_config);
+ if (tmp < 0)
+ return tmp;
+ if (active_config == -1)
+ device_configured = 0;
+ }
+
+ __get_usbfs_path(dev, path);
+ fd = open(path, O_RDWR);
+ if (fd < 0 && errno == EACCES) {
+ fd = open(path, O_RDONLY);
+ /* if we only have read-only access to the device, we cannot
+ * send a control message to determine the active config. just
+ * assume the first one is active. */
+ active_config = -1;
+ }
+
+ if (fd < 0) {
+ usbi_err(DEVICE_CTX(dev), "open failed, ret=%d errno=%d", fd, errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ if (!sysfs_can_relate_devices) {
+ if (active_config == -1) {
+ /* if we only have read-only access to the device, we cannot
+ * send a control message to determine the active config. just
+ * assume the first one is active. */
+ usbi_warn(DEVICE_CTX(dev), "access to %s is read-only; cannot "
+ "determine active configuration descriptor", path);
+ } else {
+ active_config = usbfs_get_active_config(dev, fd);
+ if (active_config == LIBUSB_ERROR_IO) {
+ /* buggy devices sometimes fail to report their active config.
+ * assume unconfigured and continue the probing */
+ usbi_warn(DEVICE_CTX(dev), "couldn't query active "
+ "configuration, assumung unconfigured");
+ device_configured = 0;
+ } else if (active_config < 0) {
+ close(fd);
+ return active_config;
+ } else if (active_config == 0) {
+ /* some buggy devices have a configuration 0, but we're
+ * reaching into the corner of a corner case here, so let's
+ * not support buggy devices in these circumstances.
+ * stick to the specs: a configuration value of 0 means
+ * unconfigured. */
+ usbi_dbg("active cfg 0? assuming unconfigured device");
+ device_configured = 0;
+ }
+ }
+ }
+
+ dev_buf = malloc(DEVICE_DESC_LENGTH);
+ if (!dev_buf) {
+ close(fd);
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ r = read(fd, dev_buf, DEVICE_DESC_LENGTH);
+ if (r < 0) {
+ usbi_err(DEVICE_CTX(dev),
+ "read descriptor failed ret=%d errno=%d", fd, errno);
+ free(dev_buf);
+ close(fd);
+ return LIBUSB_ERROR_IO;
+ } else if (r < DEVICE_DESC_LENGTH) {
+ usbi_err(DEVICE_CTX(dev), "short descriptor read (%d)", r);
+ free(dev_buf);
+ close(fd);
+ return LIBUSB_ERROR_IO;
+ }
+
+ /* bit of a hack: set num_configurations now because cache_active_config()
+ * calls usbi_get_config_index_by_value() which uses it */
+ dev->num_configurations = dev_buf[DEVICE_DESC_LENGTH - 1];
+
+ if (device_configured) {
+ r = cache_active_config(dev, fd, active_config);
+ if (r < 0) {
+ close(fd);
+ free(dev_buf);
+ return r;
+ }
+ }
+
+ close(fd);
+ priv->dev_descriptor = dev_buf;
+ return 0;
+}
+
+static int enumerate_device(struct libusb_context *ctx,
+ struct discovered_devs **_discdevs, uint8_t busnum, uint8_t devaddr,
+ const char *sysfs_dir)
+{
+ struct discovered_devs *discdevs;
+ unsigned long session_id;
+ int need_unref = 0;
+ struct libusb_device *dev;
+ int r = 0;
+
+ /* FIXME: session ID is not guaranteed unique as addresses can wrap and
+ * will be reused. instead we should add a simple sysfs attribute with
+ * a session ID. */
+ session_id = busnum << 8 | devaddr;
+ usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr,
+ session_id);
+
+ dev = usbi_get_device_by_session_id(ctx, session_id);
+ if (dev) {
+ usbi_dbg("using existing device for %d/%d (session %ld)",
+ busnum, devaddr, session_id);
+ } else {
+ usbi_dbg("allocating new device for %d/%d (session %ld)",
+ busnum, devaddr, session_id);
+ dev = usbi_alloc_device(ctx, session_id);
+ if (!dev)
+ return LIBUSB_ERROR_NO_MEM;
+ need_unref = 1;
+ r = initialize_device(dev, busnum, devaddr, sysfs_dir);
+ if (r < 0)
+ goto out;
+ r = usbi_sanitize_device(dev);
+ if (r < 0)
+ goto out;
+ }
+
+ discdevs = discovered_devs_append(*_discdevs, dev);
+ if (!discdevs)
+ r = LIBUSB_ERROR_NO_MEM;
+ else
+ *_discdevs = discdevs;
+
+out:
+ if (need_unref)
+ libusb_unref_device(dev);
+ return r;
+}
+
+/* open a bus directory and adds all discovered devices to discdevs. on
+ * failure (non-zero return) the pre-existing discdevs should be destroyed
+ * (and devices freed). on success, the new discdevs pointer should be used
+ * as it may have been moved. */
+static int usbfs_scan_busdir(struct libusb_context *ctx,
+ struct discovered_devs **_discdevs, uint8_t busnum)
+{
+ DIR *dir;
+ char dirpath[PATH_MAX];
+ struct dirent *entry;
+ struct discovered_devs *discdevs = *_discdevs;
+ int r = 0;
+
+ snprintf(dirpath, PATH_MAX, "%s/%03d", usbfs_path, busnum);
+ usbi_dbg("%s", dirpath);
+ dir = opendir(dirpath);
+ if (!dir) {
+ usbi_err(ctx, "opendir '%s' failed, errno=%d", dirpath, errno);
+ /* FIXME: should handle valid race conditions like hub unplugged
+ * during directory iteration - this is not an error */
+ return LIBUSB_ERROR_IO;
+ }
+
+ while ((entry = readdir(dir))) {
+ int devaddr;
+
+ if (entry->d_name[0] == '.')
+ continue;
+
+ devaddr = atoi(entry->d_name);
+ if (devaddr == 0) {
+ usbi_dbg("unknown dir entry %s", entry->d_name);
+ continue;
+ }
+
+ r = enumerate_device(ctx, &discdevs, busnum, (uint8_t) devaddr, NULL);
+ if (r < 0)
+ goto out;
+ }
+
+ *_discdevs = discdevs;
+out:
+ closedir(dir);
+ return r;
+}
+
+static int usbfs_get_device_list(struct libusb_context *ctx,
+ struct discovered_devs **_discdevs)
+{
+ struct dirent *entry;
+ DIR *buses = opendir(usbfs_path);
+ struct discovered_devs *discdevs = *_discdevs;
+ int r = 0;
+
+ if (!buses) {
+ usbi_err(ctx, "opendir buses failed errno=%d", errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ while ((entry = readdir(buses))) {
+ struct discovered_devs *discdevs_new = discdevs;
+ int busnum;
+
+ if (entry->d_name[0] == '.')
+ continue;
+
+ busnum = atoi(entry->d_name);
+ if (busnum == 0) {
+ usbi_dbg("unknown dir entry %s", entry->d_name);
+ continue;
+ }
+
+ r = usbfs_scan_busdir(ctx, &discdevs_new, busnum);
+ if (r < 0)
+ goto out;
+ discdevs = discdevs_new;
+ }
+
+out:
+ closedir(buses);
+ *_discdevs = discdevs;
+ return r;
+
+}
+
+static int sysfs_scan_device(struct libusb_context *ctx,
+ struct discovered_devs **_discdevs, const char *devname,
+ int *usbfs_fallback)
+{
+ int r;
+ FILE *fd;
+ char filename[PATH_MAX];
+ int busnum;
+ int devaddr;
+
+ usbi_dbg("scan %s", devname);
+
+ /* determine descriptors presence ahead of time, we need to know this
+ * when we reach initialize_device */
+ if (sysfs_has_descriptors == -1) {
+ struct stat statbuf;
+
+ snprintf(filename, PATH_MAX, "%s/%s/descriptors", SYSFS_DEVICE_PATH,
+ devname);
+ r = stat(filename, &statbuf);
+ if (r == 0 && S_ISREG(statbuf.st_mode)) {
+ usbi_dbg("sysfs descriptors available");
+ sysfs_has_descriptors = 1;
+ } else {
+ usbi_dbg("sysfs descriptors not available");
+ sysfs_has_descriptors = 0;
+ }
+ }
+
+ snprintf(filename, PATH_MAX, "%s/%s/busnum", SYSFS_DEVICE_PATH, devname);
+ fd = fopen(filename, "r");
+ if (!fd) {
+ if (errno == ENOENT) {
+ usbi_dbg("busnum not found, cannot relate sysfs to usbfs, "
+ "falling back on pure usbfs");
+ sysfs_can_relate_devices = 0;
+ *usbfs_fallback = 1;
+ return LIBUSB_ERROR_OTHER;
+ }
+ usbi_err(ctx, "open busnum failed, errno=%d", errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ sysfs_can_relate_devices = 1;
+
+ r = fscanf(fd, "%d", &busnum);
+ fclose(fd);
+ if (r != 1) {
+ usbi_err(ctx, "fscanf busnum returned %d, errno=%d", r, errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ snprintf(filename, PATH_MAX, "%s/%s/devnum", SYSFS_DEVICE_PATH, devname);
+ fd = fopen(filename, "r");
+ if (!fd) {
+ usbi_err(ctx, "open devnum failed, errno=%d", errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ r = fscanf(fd, "%d", &devaddr);
+ fclose(fd);
+ if (r != 1) {
+ usbi_err(ctx, "fscanf devnum returned %d, errno=%d", r, errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ usbi_dbg("bus=%d dev=%d", busnum, devaddr);
+ if (busnum > 255 || devaddr > 255)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ return enumerate_device(ctx, _discdevs, busnum & 0xff, devaddr & 0xff,
+ devname);
+}
+
+static int sysfs_get_device_list(struct libusb_context *ctx,
+ struct discovered_devs **_discdevs, int *usbfs_fallback)
+{
+ struct discovered_devs *discdevs = *_discdevs;
+ DIR *devices = opendir(SYSFS_DEVICE_PATH);
+ struct dirent *entry;
+ int r = 0;
+
+ if (!devices) {
+ usbi_err(ctx, "opendir devices failed errno=%d", errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ while ((entry = readdir(devices))) {
+ struct discovered_devs *discdevs_new = discdevs;
+
+ if ((!isdigit(entry->d_name[0]) && strncmp(entry->d_name, "usb", 3))
+ || strchr(entry->d_name, ':'))
+ continue;
+
+ r = sysfs_scan_device(ctx, &discdevs_new, entry->d_name,
+ usbfs_fallback);
+ if (r < 0)
+ goto out;
+ discdevs = discdevs_new;
+ }
+
+out:
+ closedir(devices);
+ *_discdevs = discdevs;
+ return r;
+}
+
+static int op_get_device_list(struct libusb_context *ctx,
+ struct discovered_devs **_discdevs)
+{
+ /* we can retrieve device list and descriptors from sysfs or usbfs.
+ * sysfs is preferable, because if we use usbfs we end up resuming
+ * any autosuspended USB devices. however, sysfs is not available
+ * everywhere, so we need a usbfs fallback too.
+ *
+ * as described in the "sysfs vs usbfs" comment, sometimes we have
+ * sysfs but not enough information to relate sysfs devices to usbfs
+ * nodes. the usbfs_fallback variable is used to indicate that we should
+ * fall back on usbfs.
+ */
+ if (sysfs_can_relate_devices != 0) {
+ int usbfs_fallback = 0;
+ int r = sysfs_get_device_list(ctx, _discdevs, &usbfs_fallback);
+ if (!usbfs_fallback)
+ return r;
+ }
+
+ return usbfs_get_device_list(ctx, _discdevs);
+}
+
+static int op_open(struct libusb_device_handle *handle)
+{
+ struct linux_device_handle_priv *hpriv = __device_handle_priv(handle);
+ char filename[PATH_MAX];
+
+ __get_usbfs_path(handle->dev, filename);
+ hpriv->fd = open(filename, O_RDWR);
+ if (hpriv->fd < 0) {
+ if (errno == EACCES) {
+ usbi_err(HANDLE_CTX(handle), "libusb couldn't open USB device %s: "
+ "Permission denied.", filename);
+ usbi_err(HANDLE_CTX(handle),
+ "libusb requires write access to USB device nodes.");
+ return LIBUSB_ERROR_ACCESS;
+ } else if (errno == ENOENT) {
+ return LIBUSB_ERROR_NO_DEVICE;
+ } else {
+ usbi_err(HANDLE_CTX(handle),
+ "open failed, code %d errno %d", hpriv->fd, errno);
+ return LIBUSB_ERROR_IO;
+ }
+ }
+
+ return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
+}
+
+static void op_close(struct libusb_device_handle *dev_handle)
+{
+ int fd = __device_handle_priv(dev_handle)->fd;
+ usbi_remove_pollfd(HANDLE_CTX(dev_handle), fd);
+ close(fd);
+}
+
+static int op_get_configuration(struct libusb_device_handle *handle,
+ int *config)
+{
+ int r;
+ if (sysfs_can_relate_devices != 1)
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+
+ r = sysfs_get_active_config(handle->dev, config);
+ if (*config == -1)
+ *config = 0;
+
+ return 0;
+}
+
+static int op_set_configuration(struct libusb_device_handle *handle, int config)
+{
+ struct linux_device_priv *priv = __device_priv(handle->dev);
+ int fd = __device_handle_priv(handle)->fd;
+ int r = ioctl(fd, IOCTL_USBFS_SETCONFIG, &config);
+ if (r) {
+ if (errno == EINVAL)
+ return LIBUSB_ERROR_NOT_FOUND;
+ else if (errno == EBUSY)
+ return LIBUSB_ERROR_BUSY;
+ else if (errno == ENODEV)
+ return LIBUSB_ERROR_NO_DEVICE;
+
+ usbi_err(HANDLE_CTX(handle), "failed, error %d errno %d", r, errno);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ if (!sysfs_has_descriptors) {
+ /* update our cached active config descriptor */
+ if (config == -1) {
+ if (priv->config_descriptor) {
+ free(priv->config_descriptor);
+ priv->config_descriptor = NULL;
+ }
+ } else {
+ r = cache_active_config(handle->dev, fd, config);
+ if (r < 0)
+ usbi_warn(HANDLE_CTX(handle),
+ "failed to update cached config descriptor, error %d", r);
+ }
+ }
+
+ return 0;
+}
+
+static int op_claim_interface(struct libusb_device_handle *handle, int iface)
+{
+ int fd = __device_handle_priv(handle)->fd;
+ int r = ioctl(fd, IOCTL_USBFS_CLAIMINTF, &iface);
+ if (r) {
+ if (errno == ENOENT)
+ return LIBUSB_ERROR_NOT_FOUND;
+ else if (errno == EBUSY)
+ return LIBUSB_ERROR_BUSY;
+ else if (errno == ENODEV)
+ return LIBUSB_ERROR_NO_DEVICE;
+
+ usbi_err(HANDLE_CTX(handle),
+ "claim interface failed, error %d errno %d", r, errno);
+ return LIBUSB_ERROR_OTHER;
+ }
+ return 0;
+}
+
+static int op_release_interface(struct libusb_device_handle *handle, int iface)
+{
+ int fd = __device_handle_priv(handle)->fd;
+ int r = ioctl(fd, IOCTL_USBFS_RELEASEINTF, &iface);
+ if (r) {
+ if (errno == ENODEV)
+ return LIBUSB_ERROR_NO_DEVICE;
+
+ usbi_err(HANDLE_CTX(handle),
+ "release interface failed, error %d errno %d", r, errno);
+ return LIBUSB_ERROR_OTHER;
+ }
+ return 0;
+}
+
+static int op_set_interface(struct libusb_device_handle *handle, int iface,
+ int altsetting)
+{
+ int fd = __device_handle_priv(handle)->fd;
+ struct usbfs_setinterface setintf;
+ int r;
+
+ setintf.interface = iface;
+ setintf.altsetting = altsetting;
+ r = ioctl(fd, IOCTL_USBFS_SETINTF, &setintf);
+ if (r) {
+ if (errno == EINVAL)
+ return LIBUSB_ERROR_NOT_FOUND;
+ else if (errno == ENODEV)
+ return LIBUSB_ERROR_NO_DEVICE;
+
+ usbi_err(HANDLE_CTX(handle),
+ "setintf failed error %d errno %d", r, errno);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ return 0;
+}
+
+static int op_clear_halt(struct libusb_device_handle *handle,
+ unsigned char endpoint)
+{
+ int fd = __device_handle_priv(handle)->fd;
+ unsigned int _endpoint = endpoint;
+ int r = ioctl(fd, IOCTL_USBFS_CLEAR_HALT, &_endpoint);
+ if (r) {
+ if (errno == ENOENT)
+ return LIBUSB_ERROR_NOT_FOUND;
+ else if (errno == ENODEV)
+ return LIBUSB_ERROR_NO_DEVICE;
+
+ usbi_err(HANDLE_CTX(handle),
+ "clear_halt failed error %d errno %d", r, errno);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ return 0;
+}
+
+static int op_reset_device(struct libusb_device_handle *handle)
+{
+ int fd = __device_handle_priv(handle)->fd;
+ int r = ioctl(fd, IOCTL_USBFS_RESET, NULL);
+ if (r) {
+ if (errno == ENODEV)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ usbi_err(HANDLE_CTX(handle),
+ "reset failed error %d errno %d", r, errno);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ return 0;
+}
+
+static int op_kernel_driver_active(struct libusb_device_handle *handle,
+ int interface)
+{
+ int fd = __device_handle_priv(handle)->fd;
+ struct usbfs_getdriver getdrv;
+ int r;
+
+ getdrv.interface = interface;
+ r = ioctl(fd, IOCTL_USBFS_GETDRIVER, &getdrv);
+ if (r) {
+ if (errno == ENODATA)
+ return 0;
+ else if (errno == ENODEV)
+ return LIBUSB_ERROR_NO_DEVICE;
+
+ usbi_err(HANDLE_CTX(handle),
+ "get driver failed error %d errno %d", r, errno);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ return 1;
+}
+
+static int op_detach_kernel_driver(struct libusb_device_handle *handle,
+ int interface)
+{
+ int fd = __device_handle_priv(handle)->fd;
+ struct usbfs_ioctl command;
+ int r;
+
+ command.ifno = interface;
+ command.ioctl_code = IOCTL_USBFS_DISCONNECT;
+ command.data = NULL;
+
+ r = ioctl(fd, IOCTL_USBFS_IOCTL, &command);
+ if (r) {
+ if (errno == ENODATA)
+ return LIBUSB_ERROR_NOT_FOUND;
+ else if (errno == EINVAL)
+ return LIBUSB_ERROR_INVALID_PARAM;
+ else if (errno == ENODEV)
+ return LIBUSB_ERROR_NO_DEVICE;
+
+ usbi_err(HANDLE_CTX(handle),
+ "detach failed error %d errno %d", r, errno);
+ return LIBUSB_ERROR_OTHER;
+ }
+
+ return 0;
+}
+
+static int op_attach_kernel_driver(struct libusb_device_handle *handle,
+ int interface)
+{
+ int fd = __device_handle_priv(handle)->fd;
+ struct usbfs_ioctl command;
+ int r;
+
+ command.ifno = interface;
+ command.ioctl_code = IOCTL_USBFS_CONNECT;
+ command.data = NULL;
+
+ r = ioctl(fd, IOCTL_USBFS_IOCTL, &command);
+ if (r < 0) {
+ if (errno == ENODATA)
+ return LIBUSB_ERROR_NOT_FOUND;
+ else if (errno == EINVAL)
+ return LIBUSB_ERROR_INVALID_PARAM;
+ else if (errno == ENODEV)
+ return LIBUSB_ERROR_NO_DEVICE;
+ else if (errno == EBUSY)
+ return LIBUSB_ERROR_BUSY;
+
+ usbi_err(HANDLE_CTX(handle),
+ "attach failed error %d errno %d", r, errno);
+ return LIBUSB_ERROR_OTHER;
+ } else if (r == 0) {
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ return 0;
+}
+
+static void op_destroy_device(struct libusb_device *dev)
+{
+ struct linux_device_priv *priv = __device_priv(dev);
+ if (!sysfs_has_descriptors) {
+ if (priv->dev_descriptor)
+ free(priv->dev_descriptor);
+ if (priv->config_descriptor)
+ free(priv->config_descriptor);
+ }
+ if (priv->sysfs_dir)
+ free(priv->sysfs_dir);
+}
+
+static void free_iso_urbs(struct linux_transfer_priv *tpriv)
+{
+ int i;
+ for (i = 0; i < tpriv->num_urbs; i++) {
+ struct usbfs_urb *urb = tpriv->iso_urbs[i];
+ if (!urb)
+ break;
+ free(urb);
+ }
+
+ free(tpriv->iso_urbs);
+ tpriv->iso_urbs = NULL;
+}
+
+static int submit_bulk_transfer(struct usbi_transfer *itransfer,
+ unsigned char urb_type)
+{
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+ struct linux_device_handle_priv *dpriv =
+ __device_handle_priv(transfer->dev_handle);
+ struct usbfs_urb *urbs;
+ int is_out = (transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK)
+ == LIBUSB_ENDPOINT_OUT;
+ int r;
+ int i;
+ size_t alloc_size;
+
+ if (tpriv->urbs)
+ return LIBUSB_ERROR_BUSY;
+
+ /* usbfs places a 16kb limit on bulk URBs. we divide up larger requests
+ * into smaller units to meet such restriction, then fire off all the
+ * units at once. it would be simpler if we just fired one unit at a time,
+ * but there is a big performance gain through doing it this way. */
+ int num_urbs = transfer->length / MAX_BULK_BUFFER_LENGTH;
+ int last_urb_partial = 0;
+
+ if (transfer->length == 0) {
+ num_urbs = 1;
+ } else if ((transfer->length % MAX_BULK_BUFFER_LENGTH) > 0) {
+ last_urb_partial = 1;
+ num_urbs++;
+ }
+ usbi_dbg("need %d urbs for new transfer with length %d", num_urbs,
+ transfer->length);
+ alloc_size = num_urbs * sizeof(struct usbfs_urb);
+ urbs = malloc(alloc_size);
+ if (!urbs)
+ return LIBUSB_ERROR_NO_MEM;
+ memset(urbs, 0, alloc_size);
+ tpriv->urbs = urbs;
+ tpriv->num_urbs = num_urbs;
+ tpriv->num_retired = 0;
+ tpriv->reap_action = NORMAL;
+ tpriv->reap_status = LIBUSB_TRANSFER_COMPLETED;
+
+ for (i = 0; i < num_urbs; i++) {
+ struct usbfs_urb *urb = &urbs[i];
+ urb->usercontext = itransfer;
+ urb->type = urb_type;
+ urb->endpoint = transfer->endpoint;
+ urb->buffer = transfer->buffer + (i * MAX_BULK_BUFFER_LENGTH);
+ if (supports_flag_bulk_continuation && !is_out)
+ urb->flags = USBFS_URB_SHORT_NOT_OK;
+ if (i == num_urbs - 1 && last_urb_partial)
+ urb->buffer_length = transfer->length % MAX_BULK_BUFFER_LENGTH;
+ else if (transfer->length == 0)
+ urb->buffer_length = 0;
+ else
+ urb->buffer_length = MAX_BULK_BUFFER_LENGTH;
+
+ if (i > 0 && supports_flag_bulk_continuation)
+ urb->flags |= USBFS_URB_BULK_CONTINUATION;
+
+ r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb);
+ if (r < 0) {
+ int j;
+
+ if (errno == ENODEV) {
+ r = LIBUSB_ERROR_NO_DEVICE;
+ } else {
+ usbi_err(TRANSFER_CTX(transfer),
+ "submiturb failed error %d errno=%d", r, errno);
+ r = LIBUSB_ERROR_IO;
+ }
+
+ /* if the first URB submission fails, we can simply free up and
+ * return failure immediately. */
+ if (i == 0) {
+ usbi_dbg("first URB failed, easy peasy");
+ free(urbs);
+ tpriv->urbs = NULL;
+ return r;
+ }
+
+ /* if it's not the first URB that failed, the situation is a bit
+ * tricky. we may need to discard all previous URBs. there are
+ * complications:
+ * - discarding is asynchronous - discarded urbs will be reaped
+ * later. the user must not have freed the transfer when the
+ * discarded URBs are reaped, otherwise libusb will be using
+ * freed memory.
+ * - the earlier URBs may have completed successfully and we do
+ * not want to throw away any data.
+ * - this URB failing may be no error; EREMOTEIO means that
+ * this transfer simply didn't need all the URBs we submitted
+ * so, we report that the transfer was submitted successfully and
+ * in case of error we discard all previous URBs. later when
+ * the final reap completes we can report error to the user,
+ * or success if an earlier URB was completed successfully.
+ */
+ tpriv->reap_action = EREMOTEIO == errno ? COMPLETED_EARLY : SUBMIT_FAILED;
+
+ /* The URBs we haven't submitted yet we count as already
+ * retired. */
+ tpriv->num_retired += num_urbs - i;
+
+ /* If we completed short then don't try to discard. */
+ if (COMPLETED_EARLY == tpriv->reap_action)
+ return 0;
+
+ for (j = 0; j < i; j++) {
+ int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &urbs[j]);
+ if (tmp && errno != EINVAL)
+ usbi_warn(TRANSFER_CTX(transfer),
+ "unrecognised discard errno %d", errno);
+ }
+
+ usbi_dbg("reporting successful submission but waiting for %d "
+ "discards before reporting error", i);
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int submit_iso_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+ struct linux_device_handle_priv *dpriv =
+ __device_handle_priv(transfer->dev_handle);
+ struct usbfs_urb **urbs;
+ size_t alloc_size;
+ int num_packets = transfer->num_iso_packets;
+ int i;
+ int this_urb_len = 0;
+ int num_urbs = 1;
+ int packet_offset = 0;
+ unsigned int packet_len;
+ unsigned char *urb_buffer = transfer->buffer;
+
+ if (tpriv->iso_urbs)
+ return LIBUSB_ERROR_BUSY;
+
+ /* usbfs places a 32kb limit on iso URBs. we divide up larger requests
+ * into smaller units to meet such restriction, then fire off all the
+ * units at once. it would be simpler if we just fired one unit at a time,
+ * but there is a big performance gain through doing it this way. */
+
+ /* calculate how many URBs we need */
+ for (i = 0; i < num_packets; i++) {
+ int space_remaining = MAX_ISO_BUFFER_LENGTH - this_urb_len;
+ packet_len = transfer->iso_packet_desc[i].length;
+
+ if (packet_len > space_remaining) {
+ num_urbs++;
+ this_urb_len = packet_len;
+ } else {
+ this_urb_len += packet_len;
+ }
+ }
+ usbi_dbg("need %d 32k URBs for transfer", num_urbs);
+
+ alloc_size = num_urbs * sizeof(*urbs);
+ urbs = malloc(alloc_size);
+ if (!urbs)
+ return LIBUSB_ERROR_NO_MEM;
+ memset(urbs, 0, alloc_size);
+
+ tpriv->iso_urbs = urbs;
+ tpriv->num_urbs = num_urbs;
+ tpriv->num_retired = 0;
+ tpriv->reap_action = NORMAL;
+ tpriv->iso_packet_offset = 0;
+
+ /* allocate + initialize each URB with the correct number of packets */
+ for (i = 0; i < num_urbs; i++) {
+ struct usbfs_urb *urb;
+ int space_remaining_in_urb = MAX_ISO_BUFFER_LENGTH;
+ int urb_packet_offset = 0;
+ unsigned char *urb_buffer_orig = urb_buffer;
+ int j;
+ int k;
+
+ /* swallow up all the packets we can fit into this URB */
+ while (packet_offset < transfer->num_iso_packets) {
+ packet_len = transfer->iso_packet_desc[packet_offset].length;
+ if (packet_len <= space_remaining_in_urb) {
+ /* throw it in */
+ urb_packet_offset++;
+ packet_offset++;
+ space_remaining_in_urb -= packet_len;
+ urb_buffer += packet_len;
+ } else {
+ /* it can't fit, save it for the next URB */
+ break;
+ }
+ }
+
+ alloc_size = sizeof(*urb)
+ + (urb_packet_offset * sizeof(struct usbfs_iso_packet_desc));
+ urb = malloc(alloc_size);
+ if (!urb) {
+ free_iso_urbs(tpriv);
+ return LIBUSB_ERROR_NO_MEM;
+ }
+ memset(urb, 0, alloc_size);
+ urbs[i] = urb;
+
+ /* populate packet lengths */
+ for (j = 0, k = packet_offset - urb_packet_offset;
+ k < packet_offset; k++, j++) {
+ packet_len = transfer->iso_packet_desc[k].length;
+ urb->iso_frame_desc[j].length = packet_len;
+ }
+
+ urb->usercontext = itransfer;
+ urb->type = USBFS_URB_TYPE_ISO;
+ /* FIXME: interface for non-ASAP data? */
+ urb->flags = USBFS_URB_ISO_ASAP;
+ urb->endpoint = transfer->endpoint;
+ urb->number_of_packets = urb_packet_offset;
+ urb->buffer = urb_buffer_orig;
+ }
+
+ /* submit URBs */
+ for (i = 0; i < num_urbs; i++) {
+ int r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urbs[i]);
+ if (r < 0) {
+ int j;
+
+ if (errno == ENODEV) {
+ r = LIBUSB_ERROR_NO_DEVICE;
+ } else {
+ usbi_err(TRANSFER_CTX(transfer),
+ "submiturb failed error %d errno=%d", r, errno);
+ r = LIBUSB_ERROR_IO;
+ }
+
+ /* if the first URB submission fails, we can simply free up and
+ * return failure immediately. */
+ if (i == 0) {
+ usbi_dbg("first URB failed, easy peasy");
+ free_iso_urbs(tpriv);
+ return r;
+ }
+
+ /* if it's not the first URB that failed, the situation is a bit
+ * tricky. we must discard all previous URBs. there are
+ * complications:
+ * - discarding is asynchronous - discarded urbs will be reaped
+ * later. the user must not have freed the transfer when the
+ * discarded URBs are reaped, otherwise libusb will be using
+ * freed memory.
+ * - the earlier URBs may have completed successfully and we do
+ * not want to throw away any data.
+ * so, in this case we discard all the previous URBs BUT we report
+ * that the transfer was submitted successfully. then later when
+ * the final discard completes we can report error to the user.
+ */
+ tpriv->reap_action = SUBMIT_FAILED;
+
+ /* The URBs we haven't submitted yet we count as already
+ * retired. */
+ tpriv->num_retired = num_urbs - i;
+ for (j = 0; j < i; j++) {
+ int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, urbs[j]);
+ if (tmp && errno != EINVAL)
+ usbi_warn(TRANSFER_CTX(transfer),
+ "unrecognised discard errno %d", errno);
+ }
+
+ usbi_dbg("reporting successful submission but waiting for %d "
+ "discards before reporting error", i);
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int submit_control_transfer(struct usbi_transfer *itransfer)
+{
+ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct linux_device_handle_priv *dpriv =
+ __device_handle_priv(transfer->dev_handle);
+ struct usbfs_urb *urb;
+ int r;
+
+ if (tpriv->urbs)
+ return LIBUSB_ERROR_BUSY;
+
+ if (transfer->length - LIBUSB_CONTROL_SETUP_SIZE > MAX_CTRL_BUFFER_LENGTH)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ urb = malloc(sizeof(struct usbfs_urb));
+ if (!urb)
+ return LIBUSB_ERROR_NO_MEM;
+ memset(urb, 0, sizeof(struct usbfs_urb));
+ tpriv->urbs = urb;
+ tpriv->reap_action = NORMAL;
+
+ urb->usercontext = itransfer;
+ urb->type = USBFS_URB_TYPE_CONTROL;
+ urb->endpoint = transfer->endpoint;
+ urb->buffer = transfer->buffer;
+ urb->buffer_length = transfer->length;
+
+ r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb);
+ if (r < 0) {
+ free(urb);
+ tpriv->urbs = NULL;
+ if (errno == ENODEV)
+ return LIBUSB_ERROR_NO_DEVICE;
+
+ usbi_err(TRANSFER_CTX(transfer),
+ "submiturb failed error %d errno=%d", r, errno);
+ return LIBUSB_ERROR_IO;
+ }
+ return 0;
+}
+
+static int op_submit_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ return submit_control_transfer(itransfer);
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_BULK);
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_INTERRUPT);
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ return submit_iso_transfer(itransfer);
+ default:
+ usbi_err(TRANSFER_CTX(transfer),
+ "unknown endpoint type %d", transfer->type);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+}
+
+static int cancel_control_transfer(struct usbi_transfer *itransfer)
+{
+ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct linux_device_handle_priv *dpriv =
+ __device_handle_priv(transfer->dev_handle);
+ int r;
+
+ if (!tpriv->urbs)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ tpriv->reap_action = CANCELLED;
+ r = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, tpriv->urbs);
+ if(r) {
+ if (errno == EINVAL) {
+ usbi_dbg("URB not found --> assuming ready to be reaped");
+ return 0;
+ } else {
+ usbi_err(TRANSFER_CTX(transfer),
+ "unrecognised DISCARD code %d", errno);
+ return LIBUSB_ERROR_OTHER;
+ }
+ }
+
+ return 0;
+}
+
+static int cancel_bulk_transfer(struct usbi_transfer *itransfer)
+{
+ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct linux_device_handle_priv *dpriv =
+ __device_handle_priv(transfer->dev_handle);
+ int i;
+
+ if (!tpriv->urbs)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ if (tpriv->reap_action != ERROR)
+ tpriv->reap_action = CANCELLED;
+
+ for (i = 0; i < tpriv->num_urbs; i++) {
+ int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &tpriv->urbs[i]);
+ if (tmp && errno != EINVAL)
+ usbi_warn(TRANSFER_CTX(transfer),
+ "unrecognised discard errno %d", errno);
+ }
+ return 0;
+}
+
+static int cancel_iso_transfer(struct usbi_transfer *itransfer)
+{
+ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct linux_device_handle_priv *dpriv =
+ __device_handle_priv(transfer->dev_handle);
+ int i;
+
+ if (!tpriv->iso_urbs)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ tpriv->reap_action = CANCELLED;
+ for (i = 0; i < tpriv->num_urbs; i++) {
+ int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, tpriv->iso_urbs[i]);
+ if (tmp && errno != EINVAL)
+ usbi_warn(TRANSFER_CTX(transfer),
+ "unrecognised discard errno %d", errno);
+ }
+ return 0;
+}
+
+static int op_cancel_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ return cancel_control_transfer(itransfer);
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ return cancel_bulk_transfer(itransfer);
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ return cancel_iso_transfer(itransfer);
+ default:
+ usbi_err(TRANSFER_CTX(transfer),
+ "unknown endpoint type %d", transfer->type);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+}
+
+static void op_clear_transfer_priv(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ free(tpriv->urbs);
+ tpriv->urbs = NULL;
+ break;
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ free_iso_urbs(tpriv);
+ break;
+ default:
+ usbi_err(TRANSFER_CTX(transfer),
+ "unknown endpoint type %d", transfer->type);
+ }
+}
+
+static int handle_bulk_completion(struct usbi_transfer *itransfer,
+ struct usbfs_urb *urb)
+{
+ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct linux_device_handle_priv *dpriv = __device_handle_priv(transfer->dev_handle);
+ int urb_idx = urb - tpriv->urbs;
+
+ usbi_mutex_lock(&itransfer->lock);
+ usbi_dbg("handling completion status %d of bulk urb %d/%d", urb->status,
+ urb_idx + 1, tpriv->num_urbs);
+
+ tpriv->num_retired++;
+
+ if (tpriv->reap_action != NORMAL) {
+ /* cancelled, submit_fail, or completed early */
+ usbi_dbg("abnormal reap: urb status %d", urb->status);
+
+ /* even though we're in the process of cancelling, it's possible that
+ * we may receive some data in these URBs that we don't want to lose.
+ * examples:
+ * 1. while the kernel is cancelling all the packets that make up an
+ * URB, a few of them might complete. so we get back a successful
+ * cancellation *and* some data.
+ * 2. we receive a short URB which marks the early completion condition,
+ * so we start cancelling the remaining URBs. however, we're too
+ * slow and another URB completes (or at least completes partially).
+ *
+ * When this happens, our objectives are not to lose any "surplus" data,
+ * and also to stick it at the end of the previously-received data
+ * (closing any holes), so that libusb reports the total amount of
+ * transferred data and presents it in a contiguous chunk.
+ */
+ if (urb->actual_length > 0) {
+ unsigned char *target = transfer->buffer + itransfer->transferred;
+ usbi_dbg("received %d bytes of surplus data", urb->actual_length);
+ if (urb->buffer != target) {
+ usbi_dbg("moving surplus data from offset %d to offset %d",
+ (unsigned char *) urb->buffer - transfer->buffer,
+ target - transfer->buffer);
+ memmove(target, urb->buffer, urb->actual_length);
+ }
+ itransfer->transferred += urb->actual_length;
+ }
+
+ if (tpriv->num_retired == tpriv->num_urbs) {
+ usbi_dbg("abnormal reap: last URB handled, reporting");
+ if (tpriv->reap_action != COMPLETED_EARLY &&
+ tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED)
+ tpriv->reap_status = LIBUSB_TRANSFER_ERROR;
+ goto completed;
+ }
+ goto out_unlock;
+ }
+
+ if (urb->status == 0 || urb->status == -EREMOTEIO ||
+ (urb->status == -EOVERFLOW && urb->actual_length > 0))
+ itransfer->transferred += urb->actual_length;
+
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -EREMOTEIO: /* short transfer */
+ break;
+ case -EPIPE:
+ usbi_dbg("detected endpoint stall");
+ if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED)
+ tpriv->reap_status = LIBUSB_TRANSFER_STALL;
+ goto cancel_remaining;
+ case -EOVERFLOW:
+ /* overflow can only ever occur in the last urb */
+ usbi_dbg("overflow, actual_length=%d", urb->actual_length);
+ if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED)
+ tpriv->reap_status = LIBUSB_TRANSFER_OVERFLOW;
+ goto completed;
+ case -ETIME:
+ case -EPROTO:
+ case -EILSEQ:
+ /* These can happen on *any* urb of a multi-urb transfer, so
+ * save a status and tear down rest of the transfer */
+ usbi_dbg("low level error %d", urb->status);
+ tpriv->reap_action = ERROR;
+ if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED)
+ tpriv->reap_status = LIBUSB_TRANSFER_ERROR;
+ goto cancel_remaining;
+ default:
+ usbi_warn(ITRANSFER_CTX(itransfer),
+ "unrecognised urb status %d", urb->status);
+ if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED)
+ tpriv->reap_status = LIBUSB_TRANSFER_ERROR;
+ goto cancel_remaining;
+ }
+
+ /* if we're the last urb or we got less data than requested then we're
+ * done */
+ if (urb_idx == tpriv->num_urbs - 1) {
+ usbi_dbg("last URB in transfer --> complete!");
+ goto completed;
+ } else if (urb->actual_length < urb->buffer_length) {
+ usbi_dbg("short transfer %d/%d --> complete!",
+ urb->actual_length, urb->buffer_length);
+ if (tpriv->reap_action == NORMAL)
+ tpriv->reap_action = COMPLETED_EARLY;
+ } else
+ goto out_unlock;
+
+cancel_remaining:
+ if (tpriv->num_retired == tpriv->num_urbs) /* nothing to cancel */
+ goto completed;
+
+ /* cancel remaining urbs and wait for their completion before
+ * reporting results */
+ while (++urb_idx < tpriv->num_urbs) {
+ /* remaining URBs with continuation flag are
+ * automatically cancelled by the kernel */
+ if (tpriv->urbs[urb_idx].flags & USBFS_URB_BULK_CONTINUATION)
+ continue;
+ int tmp = ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, &tpriv->urbs[urb_idx]);
+ if (tmp && errno != EINVAL)
+ usbi_warn(TRANSFER_CTX(transfer),
+ "unrecognised discard errno %d", errno);
+ }
+
+out_unlock:
+ usbi_mutex_unlock(&itransfer->lock);
+ return 0;
+
+completed:
+ free(tpriv->urbs);
+ tpriv->urbs = NULL;
+ usbi_mutex_unlock(&itransfer->lock);
+ return CANCELLED == tpriv->reap_action ?
+ usbi_handle_transfer_cancellation(itransfer) :
+ usbi_handle_transfer_completion(itransfer, tpriv->reap_status);
+}
+
+static int handle_iso_completion(struct usbi_transfer *itransfer,
+ struct usbfs_urb *urb)
+{
+ struct libusb_transfer *transfer =
+ __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+ int num_urbs = tpriv->num_urbs;
+ int urb_idx = 0;
+ int i;
+
+ usbi_mutex_lock(&itransfer->lock);
+ for (i = 0; i < num_urbs; i++) {
+ if (urb == tpriv->iso_urbs[i]) {
+ urb_idx = i + 1;
+ break;
+ }
+ }
+ if (urb_idx == 0) {
+ usbi_err(TRANSFER_CTX(transfer), "could not locate urb!");
+ usbi_mutex_unlock(&itransfer->lock);
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ usbi_dbg("handling completion status %d of iso urb %d/%d", urb->status,
+ urb_idx, num_urbs);
+
+ if (urb->status == 0) {
+ /* copy isochronous results back in */
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ struct usbfs_iso_packet_desc *urb_desc = &urb->iso_frame_desc[i];
+ struct libusb_iso_packet_descriptor *lib_desc =
+ &transfer->iso_packet_desc[tpriv->iso_packet_offset++];
+ lib_desc->status = urb_desc->status;
+ lib_desc->actual_length = urb_desc->actual_length;
+ }
+ }
+
+ tpriv->num_retired++;
+
+ if (tpriv->reap_action != NORMAL) { /* cancelled or submit_fail */
+ usbi_dbg("CANCEL: urb status %d", urb->status);
+
+ if (tpriv->num_retired == num_urbs) {
+ usbi_dbg("CANCEL: last URB handled, reporting");
+ free_iso_urbs(tpriv);
+ if (tpriv->reap_action == CANCELLED) {
+ usbi_mutex_unlock(&itransfer->lock);
+ return usbi_handle_transfer_cancellation(itransfer);
+ } else {
+ usbi_mutex_unlock(&itransfer->lock);
+ return usbi_handle_transfer_completion(itransfer,
+ LIBUSB_TRANSFER_ERROR);
+ }
+ }
+ goto out;
+ }
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ETIME:
+ case -EPROTO:
+ case -EILSEQ:
+ usbi_dbg("low-level USB error %d", urb->status);
+ break;
+ default:
+ usbi_warn(TRANSFER_CTX(transfer),
+ "unrecognised urb status %d", urb->status);
+ break;
+ }
+
+ /* if we're the last urb or we got less data than requested then we're
+ * done */
+ if (urb_idx == num_urbs) {
+ usbi_dbg("last URB in transfer --> complete!");
+ free_iso_urbs(tpriv);
+ usbi_mutex_unlock(&itransfer->lock);
+ return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
+ }
+
+out:
+ usbi_mutex_unlock(&itransfer->lock);
+ return 0;
+}
+
+static int handle_control_completion(struct usbi_transfer *itransfer,
+ struct usbfs_urb *urb)
+{
+ struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
+ int status;
+
+ usbi_mutex_lock(&itransfer->lock);
+ usbi_dbg("handling completion status %d", urb->status);
+
+ if (urb->status == 0)
+ itransfer->transferred += urb->actual_length;
+
+ if (tpriv->reap_action == CANCELLED) {
+ if (urb->status != 0 && urb->status != -ENOENT)
+ usbi_warn(ITRANSFER_CTX(itransfer),
+ "cancel: unrecognised urb status %d", urb->status);
+ free(tpriv->urbs);
+ tpriv->urbs = NULL;
+ usbi_mutex_unlock(&itransfer->lock);
+ return usbi_handle_transfer_cancellation(itransfer);
+ }
+
+ switch (urb->status) {
+ case 0:
+ itransfer->transferred = urb->actual_length;
+ status = LIBUSB_TRANSFER_COMPLETED;
+ break;
+ case -EPIPE:
+ usbi_dbg("unsupported control request");
+ status = LIBUSB_TRANSFER_STALL;
+ break;
+ case -ETIME:
+ case -EPROTO:
+ case -EILSEQ:
+ usbi_dbg("low-level bus error occurred");
+ status = LIBUSB_TRANSFER_ERROR;
+ break;
+ default:
+ usbi_warn(ITRANSFER_CTX(itransfer),
+ "unrecognised urb status %d", urb->status);
+ status = LIBUSB_TRANSFER_ERROR;
+ break;
+ }
+
+ free(tpriv->urbs);
+ tpriv->urbs = NULL;
+ usbi_mutex_unlock(&itransfer->lock);
+ return usbi_handle_transfer_completion(itransfer, status);
+}
+
+static int reap_for_handle(struct libusb_device_handle *handle)
+{
+ struct linux_device_handle_priv *hpriv = __device_handle_priv(handle);
+ int r;
+ struct usbfs_urb *urb;
+ struct usbi_transfer *itransfer;
+ struct libusb_transfer *transfer;
+
+ r = ioctl(hpriv->fd, IOCTL_USBFS_REAPURBNDELAY, &urb);
+ if (r == -1 && errno == EAGAIN)
+ return 1;
+ if (r < 0) {
+ if (errno == ENODEV)
+ return LIBUSB_ERROR_NO_DEVICE;
+
+ usbi_err(HANDLE_CTX(handle), "reap failed error %d errno=%d",
+ r, errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ itransfer = urb->usercontext;
+ transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+ usbi_dbg("urb type=%d status=%d transferred=%d", urb->type, urb->status,
+ urb->actual_length);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ return handle_iso_completion(itransfer, urb);
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ return handle_bulk_completion(itransfer, urb);
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ return handle_control_completion(itransfer, urb);
+ default:
+ usbi_err(HANDLE_CTX(handle), "unrecognised endpoint type %x",
+ transfer->type);
+ return LIBUSB_ERROR_OTHER;
+ }
+}
+
+static int op_handle_events(struct libusb_context *ctx,
+ struct pollfd *fds, nfds_t nfds, int num_ready)
+{
+ int r;
+ int i = 0;
+
+ usbi_mutex_lock(&ctx->open_devs_lock);
+ for (i = 0; i < nfds && num_ready > 0; i++) {
+ struct pollfd *pollfd = &fds[i];
+ struct libusb_device_handle *handle;
+ struct linux_device_handle_priv *hpriv = NULL;
+
+ if (!pollfd->revents)
+ continue;
+
+ num_ready--;
+ list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
+ hpriv = __device_handle_priv(handle);
+ if (hpriv->fd == pollfd->fd)
+ break;
+ }
+
+ if (pollfd->revents & POLLERR) {
+ usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd);
+ usbi_handle_disconnect(handle);
+ continue;
+ }
+
+ r = reap_for_handle(handle);
+ if (r == 1 || r == LIBUSB_ERROR_NO_DEVICE)
+ continue;
+ else if (r < 0)
+ goto out;
+ }
+
+ r = 0;
+out:
+ usbi_mutex_unlock(&ctx->open_devs_lock);
+ return r;
+}
+
+static int op_clock_gettime(int clk_id, struct timespec *tp)
+{
+ switch (clk_id) {
+ case USBI_CLOCK_MONOTONIC:
+ return clock_gettime(monotonic_clkid, tp);
+ case USBI_CLOCK_REALTIME:
+ return clock_gettime(CLOCK_REALTIME, tp);
+ default:
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+}
+
+#ifdef USBI_TIMERFD_AVAILABLE
+static clockid_t op_get_timerfd_clockid(void)
+{
+ return monotonic_clkid;
+
+}
+#endif
+
+const struct usbi_os_backend linux_usbfs_backend = {
+ .name = "Linux usbfs",
+ .init = op_init,
+ .exit = NULL,
+ .get_device_list = op_get_device_list,
+ .get_device_descriptor = op_get_device_descriptor,
+ .get_active_config_descriptor = op_get_active_config_descriptor,
+ .get_config_descriptor = op_get_config_descriptor,
+
+ .open = op_open,
+ .close = op_close,
+ .get_configuration = op_get_configuration,
+ .set_configuration = op_set_configuration,
+ .claim_interface = op_claim_interface,
+ .release_interface = op_release_interface,
+
+ .set_interface_altsetting = op_set_interface,
+ .clear_halt = op_clear_halt,
+ .reset_device = op_reset_device,
+
+ .kernel_driver_active = op_kernel_driver_active,
+ .detach_kernel_driver = op_detach_kernel_driver,
+ .attach_kernel_driver = op_attach_kernel_driver,
+
+ .destroy_device = op_destroy_device,
+
+ .submit_transfer = op_submit_transfer,
+ .cancel_transfer = op_cancel_transfer,
+ .clear_transfer_priv = op_clear_transfer_priv,
+
+ .handle_events = op_handle_events,
+
+ .clock_gettime = op_clock_gettime,
+
+#ifdef USBI_TIMERFD_AVAILABLE
+ .get_timerfd_clockid = op_get_timerfd_clockid,
+#endif
+
+ .device_priv_size = sizeof(struct linux_device_priv),
+ .device_handle_priv_size = sizeof(struct linux_device_handle_priv),
+ .transfer_priv_size = sizeof(struct linux_transfer_priv),
+ .add_iso_packet_size = 0,
+};
+
diff --git a/libusb-1.0/libusb/os/linux_usbfs.h b/libusb-1.0/libusb/os/linux_usbfs.h
new file mode 100644
index 0000000..bd02edc
--- /dev/null
+++ b/libusb-1.0/libusb/os/linux_usbfs.h
@@ -0,0 +1,138 @@
+/*
+ * usbfs header structures
+ * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LIBUSB_USBFS_H__
+#define __LIBUSB_USBFS_H__
+
+#define SYSFS_DEVICE_PATH "/sys/bus/usb/devices"
+
+struct usbfs_ctrltransfer {
+ /* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */
+ uint8_t bmRequestType;
+ uint8_t bRequest;
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength;
+
+ uint32_t timeout; /* in milliseconds */
+
+ /* pointer to data */
+ void *data;
+};
+
+struct usbfs_bulktransfer {
+ /* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */
+ unsigned int ep;
+ unsigned int len;
+ unsigned int timeout; /* in milliseconds */
+
+ /* pointer to data */
+ void *data;
+};
+
+struct usbfs_setinterface {
+ /* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */
+ unsigned int interface;
+ unsigned int altsetting;
+};
+
+#define USBFS_MAXDRIVERNAME 255
+
+struct usbfs_getdriver {
+ unsigned int interface;
+ char driver[USBFS_MAXDRIVERNAME + 1];
+};
+
+#define USBFS_URB_SHORT_NOT_OK 0x01
+#define USBFS_URB_ISO_ASAP 0x02
+#define USBFS_URB_BULK_CONTINUATION 0x04
+#define USBFS_URB_QUEUE_BULK 0x10
+
+enum usbfs_urb_type {
+ USBFS_URB_TYPE_ISO = 0,
+ USBFS_URB_TYPE_INTERRUPT = 1,
+ USBFS_URB_TYPE_CONTROL = 2,
+ USBFS_URB_TYPE_BULK = 3,
+};
+
+struct usbfs_iso_packet_desc {
+ unsigned int length;
+ unsigned int actual_length;
+ unsigned int status;
+};
+
+#define MAX_ISO_BUFFER_LENGTH 32768
+#define MAX_BULK_BUFFER_LENGTH 16384
+#define MAX_CTRL_BUFFER_LENGTH 4096
+
+struct usbfs_urb {
+ unsigned char type;
+ unsigned char endpoint;
+ int status;
+ unsigned int flags;
+ void *buffer;
+ int buffer_length;
+ int actual_length;
+ int start_frame;
+ int number_of_packets;
+ int error_count;
+ unsigned int signr;
+ void *usercontext;
+ struct usbfs_iso_packet_desc iso_frame_desc[0];
+};
+
+struct usbfs_connectinfo {
+ unsigned int devnum;
+ unsigned char slow;
+};
+
+struct usbfs_ioctl {
+ int ifno; /* interface 0..N ; negative numbers reserved */
+ int ioctl_code; /* MUST encode size + direction of data so the
+ * macros in <asm/ioctl.h> give correct values */
+ void *data; /* param buffer (in, or out) */
+};
+
+struct usbfs_hub_portinfo {
+ unsigned char numports;
+ unsigned char port[127]; /* port to device num mapping */
+};
+
+#define IOCTL_USBFS_CONTROL _IOWR('U', 0, struct usbfs_ctrltransfer)
+#define IOCTL_USBFS_BULK _IOWR('U', 2, struct usbfs_bulktransfer)
+#define IOCTL_USBFS_RESETEP _IOR('U', 3, unsigned int)
+#define IOCTL_USBFS_SETINTF _IOR('U', 4, struct usbfs_setinterface)
+#define IOCTL_USBFS_SETCONFIG _IOR('U', 5, unsigned int)
+#define IOCTL_USBFS_GETDRIVER _IOW('U', 8, struct usbfs_getdriver)
+#define IOCTL_USBFS_SUBMITURB _IOR('U', 10, struct usbfs_urb)
+#define IOCTL_USBFS_DISCARDURB _IO('U', 11)
+#define IOCTL_USBFS_REAPURB _IOW('U', 12, void *)
+#define IOCTL_USBFS_REAPURBNDELAY _IOW('U', 13, void *)
+#define IOCTL_USBFS_CLAIMINTF _IOR('U', 15, unsigned int)
+#define IOCTL_USBFS_RELEASEINTF _IOR('U', 16, unsigned int)
+#define IOCTL_USBFS_CONNECTINFO _IOW('U', 17, struct usbfs_connectinfo)
+#define IOCTL_USBFS_IOCTL _IOWR('U', 18, struct usbfs_ioctl)
+#define IOCTL_USBFS_HUB_PORTINFO _IOR('U', 19, struct usbfs_hub_portinfo)
+#define IOCTL_USBFS_RESET _IO('U', 20)
+#define IOCTL_USBFS_CLEAR_HALT _IOR('U', 21, unsigned int)
+#define IOCTL_USBFS_DISCONNECT _IO('U', 22)
+#define IOCTL_USBFS_CONNECT _IO('U', 23)
+
+#endif
diff --git a/libusb-1.0/libusb/os/poll_posix.h b/libusb-1.0/libusb/os/poll_posix.h
new file mode 100644
index 0000000..17298a5
--- /dev/null
+++ b/libusb-1.0/libusb/os/poll_posix.h
@@ -0,0 +1,12 @@
+#ifndef __LIBUSB_POLL_POSIX_H__
+#define __LIBUSB_POLL_POSIX_H__
+
+#include <unistd.h>
+#include <poll.h>
+#define usbi_write write
+#define usbi_read read
+#define usbi_close close
+#define usbi_pipe pipe
+#define usbi_poll poll
+
+#endif /* __LIBUSB_POLL_POSIX_H__ */
diff --git a/libusb-1.0/libusb/os/poll_windows.c b/libusb-1.0/libusb/os/poll_windows.c
new file mode 100644
index 0000000..55dbc18
--- /dev/null
+++ b/libusb-1.0/libusb/os/poll_windows.c
@@ -0,0 +1,857 @@
+/*
+ * poll_windows: poll compatibility wrapper for Windows
+ * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com>
+ * With contributions from Michael Plante, Orin Eman et al.
+ * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/*
+ * poll() and pipe() Windows compatibility layer for libusb 1.0
+ *
+ * The way this layer works is by using OVERLAPPED with async I/O transfers, as
+ * OVERLAPPED have an associated event which is flagged for I/O completion.
+ *
+ * For USB pollable async I/O, you would typically:
+ * - obtain a Windows HANDLE to a file or device that has been opened in
+ * OVERLAPPED mode
+ * - call usbi_create_fd with this handle to obtain a custom fd.
+ * Note that if you need simultaneous R/W access, you need to call create_fd
+ * twice, once in _O_RDONLY and once in _O_WRONLY mode to obtain 2 separate
+ * pollable fds
+ * - leave the core functions call the poll routine and flag POLLIN/POLLOUT
+ *
+ * The pipe pollable synchronous I/O works using the overlapped event associated
+ * with a fake pipe. The read/write functions are only meant to be used in that
+ * context.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <io.h>
+
+#include <libusbi.h>
+
+// Uncomment to debug the polling layer
+//#define DEBUG_POLL_WINDOWS
+#if defined(DEBUG_POLL_WINDOWS)
+#define poll_dbg usbi_dbg
+#else
+// MSVC6 cannot use a variadic argument and non MSVC
+// compilers produce warnings if parenthesis are ommitted.
+#if defined(_MSC_VER)
+#define poll_dbg
+#else
+#define poll_dbg(...)
+#endif
+#endif
+
+#if defined(_PREFAST_)
+#pragma warning(disable:28719)
+#endif
+
+#if defined(__CYGWIN__)
+// cygwin produces a warning unless these prototypes are defined
+extern int _open(char* name, int flags);
+extern int _close(int fd);
+extern int _snprintf(char *buffer, size_t count, const char *format, ...);
+#define NUL_DEVICE "/dev/null"
+#else
+#define NUL_DEVICE "NUL"
+#endif
+
+#define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0)
+
+// Workaround for MinGW-w64 multilib bug
+#if defined(_MSC_VER) || defined(_WIN64)
+#define INIT_INTERLOCKEDEXCHANGE
+#define pInterlockedExchange InterlockedExchange
+#else
+static LONG (WINAPI *pInterlockedExchange)(LONG volatile *, LONG) = NULL;
+#define INIT_INTERLOCKEDEXCHANGE if (pInterlockedExchange == NULL) { \
+ pInterlockedExchange = (LONG (WINAPI *)(LONG volatile *, LONG)) \
+ GetProcAddress(GetModuleHandle("KERNEL32"), "InterlockedExchange"); \
+ if (pInterlockedExchange == NULL) { \
+ usbi_err(NULL, "InterlockedExchange is unavailable"); \
+ return; \
+ } \
+}
+#endif
+
+// public fd data
+const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, RW_NONE};
+struct winfd poll_fd[MAX_FDS];
+// internal fd data
+struct {
+ CRITICAL_SECTION mutex; // lock for fds
+ // Additional variables for XP CancelIoEx partial emulation
+ HANDLE original_handle;
+ DWORD thread_id;
+} _poll_fd[MAX_FDS];
+
+// globals
+BOOLEAN is_polling_set = FALSE;
+#if defined(DYNAMIC_FDS)
+HANDLE fd_update = INVALID_HANDLE_VALUE; // event to notify poll of fd update
+HANDLE new_fd[MAX_FDS]; // overlapped event handles for fds created since last poll
+unsigned nb_new_fds = 0; // nb new fds created since last poll
+usbi_mutex_t new_fd_mutex; // mutex required for the above
+#endif
+LONG pipe_number = 0;
+static volatile LONG compat_spinlock = 0;
+
+// CancelIoEx, available on Vista and later only, provides the ability to cancel
+// a single transfer (OVERLAPPED) when used. As it may not be part of any of the
+// platform headers, we hook into the Kernel32 system DLL directly to seek it.
+static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
+#define CancelIoEx_Available (pCancelIoEx != NULL)
+__inline BOOL cancel_io(int _index)
+{
+ if ((_index < 0) || (_index >= MAX_FDS)) {
+ return FALSE;
+ }
+
+ if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
+ || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) {
+ return TRUE;
+ }
+ if (CancelIoEx_Available) {
+ return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped);
+ }
+ if (_poll_fd[_index].thread_id == GetCurrentThreadId()) {
+ return CancelIo(poll_fd[_index].handle);
+ }
+ usbi_warn(NULL, "Unable to cancel I/O that was started from another thread");
+ return FALSE;
+}
+
+// Init
+void init_polling(void)
+{
+ int i;
+
+ INIT_INTERLOCKEDEXCHANGE;
+ while (pInterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
+ SleepEx(0, TRUE);
+ }
+ if (!is_polling_set) {
+ pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED))
+ GetProcAddress(GetModuleHandleA("KERNEL32"), "CancelIoEx");
+ usbi_dbg("Will use CancelIo%s for I/O cancellation",
+ CancelIoEx_Available?"Ex":"");
+ for (i=0; i<MAX_FDS; i++) {
+ poll_fd[i] = INVALID_WINFD;
+ _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
+ _poll_fd[i].thread_id = 0;
+ InitializeCriticalSection(&_poll_fd[i].mutex);
+ }
+#if defined(DYNAMIC_FDS)
+ // We need to create an update event so that poll is warned when there
+ // are new/deleted fds during a timeout wait operation
+ fd_update = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (fd_update == NULL) {
+ usbi_err(NULL, "unable to create update event");
+ }
+ usbi_mutex_init(&new_fd_mutex, NULL);
+ nb_new_fds = 0;
+#endif
+ is_polling_set = TRUE;
+ }
+ compat_spinlock = 0;
+}
+
+// Internal function to retrieve the table index (and lock the fd mutex)
+int _fd_to_index_and_lock(int fd)
+{
+ int i;
+
+ if (fd <= 0)
+ return -1;
+
+ for (i=0; i<MAX_FDS; i++) {
+ if (poll_fd[i].fd == fd) {
+ EnterCriticalSection(&_poll_fd[i].mutex);
+ // fd might have changed before we got to critical
+ if (poll_fd[i].fd != fd) {
+ LeaveCriticalSection(&_poll_fd[i].mutex);
+ continue;
+ }
+ return i;
+ }
+ }
+ return -1;
+}
+
+OVERLAPPED *create_overlapped(void)
+{
+ OVERLAPPED *overlapped = calloc(1, sizeof(OVERLAPPED));
+ if (overlapped == NULL) {
+ return NULL;
+ }
+ overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if(overlapped->hEvent == NULL) {
+ free (overlapped);
+ return NULL;
+ }
+ return overlapped;
+}
+
+void free_overlapped(OVERLAPPED *overlapped)
+{
+ if (overlapped == NULL)
+ return;
+
+ if ( (overlapped->hEvent != 0)
+ && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) {
+ CloseHandle(overlapped->hEvent);
+ }
+ free(overlapped);
+}
+
+void reset_overlapped(OVERLAPPED *overlapped)
+{
+ HANDLE event_handle;
+ if (overlapped == NULL)
+ return;
+
+ event_handle = overlapped->hEvent;
+ if (event_handle != NULL) {
+ ResetEvent(event_handle);
+ }
+ memset(overlapped, 0, sizeof(OVERLAPPED));
+ overlapped->hEvent = event_handle;
+}
+
+void exit_polling(void)
+{
+ int i;
+
+ INIT_INTERLOCKEDEXCHANGE;
+ while (pInterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
+ SleepEx(0, TRUE);
+ }
+ if (is_polling_set) {
+ is_polling_set = FALSE;
+
+ for (i=0; i<MAX_FDS; i++) {
+ // Cancel any async I/O (handle can be invalid)
+ cancel_io(i);
+ // If anything was pending on that I/O, it should be
+ // terminating, and we should be able to access the fd
+ // mutex lock before too long
+ EnterCriticalSection(&_poll_fd[i].mutex);
+ if ( (poll_fd[i].fd > 0) && (poll_fd[i].handle != INVALID_HANDLE_VALUE) && (poll_fd[i].handle != 0)
+ && (GetFileType(poll_fd[i].handle) == FILE_TYPE_UNKNOWN) ) {
+ _close(poll_fd[i].fd);
+ }
+ free_overlapped(poll_fd[i].overlapped);
+ if (!CancelIoEx_Available) {
+ // Close duplicate handle
+ if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(poll_fd[i].handle);
+ }
+ }
+ poll_fd[i] = INVALID_WINFD;
+#if defined(DYNAMIC_FDS)
+ usbi_mutex_destroy(&new_fd_mutex);
+ CloseHandle(fd_update);
+ fd_update = INVALID_HANDLE_VALUE;
+#endif
+ LeaveCriticalSection(&_poll_fd[i].mutex);
+ DeleteCriticalSection(&_poll_fd[i].mutex);
+ }
+ }
+ compat_spinlock = 0;
+}
+
+/*
+ * Create a fake pipe.
+ * As libusb only uses pipes for signaling, all we need from a pipe is an
+ * event. To that extent, we create a single wfd and overlapped as a means
+ * to access that event.
+ */
+int usbi_pipe(int filedes[2])
+{
+ int i;
+ OVERLAPPED* overlapped;
+
+ CHECK_INIT_POLLING;
+
+ overlapped = calloc(1, sizeof(OVERLAPPED));
+ if (overlapped == NULL) {
+ return -1;
+ }
+ // The overlapped must have status pending for signaling to work in poll
+ overlapped->Internal = STATUS_PENDING;
+ overlapped->InternalHigh = 0;
+
+ // Read end of the "pipe"
+ filedes[0] = _open(NUL_DEVICE, _O_WRONLY);
+ if (filedes[0] < 0) {
+ usbi_err(NULL, "could not create pipe: errno %d", errno);
+ goto out1;
+ }
+ // We can use the same handle for both ends
+ filedes[1] = filedes[0];
+ poll_dbg("pipe filedes = %d", filedes[0]);
+
+ // Note: manual reset must be true (second param) as the reset occurs in read
+ overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if(!overlapped->hEvent) {
+ goto out2;
+ }
+
+ for (i=0; i<MAX_FDS; i++) {
+ if (poll_fd[i].fd < 0) {
+ EnterCriticalSection(&_poll_fd[i].mutex);
+ // fd might have been allocated before we got to critical
+ if (poll_fd[i].fd >= 0) {
+ LeaveCriticalSection(&_poll_fd[i].mutex);
+ continue;
+ }
+
+ poll_fd[i].fd = filedes[0];
+ poll_fd[i].handle = DUMMY_HANDLE;
+ poll_fd[i].overlapped = overlapped;
+ // There's no polling on the write end, so we just use READ for our needs
+ poll_fd[i].rw = RW_READ;
+ _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
+ LeaveCriticalSection(&_poll_fd[i].mutex);
+ return 0;
+ }
+ }
+
+ CloseHandle(overlapped->hEvent);
+out2:
+ _close(filedes[0]);
+out1:
+ free(overlapped);
+ return -1;
+}
+
+/*
+ * Create both an fd and an OVERLAPPED from an open Windows handle, so that
+ * it can be used with our polling function
+ * The handle MUST support overlapped transfers (usually requires CreateFile
+ * with FILE_FLAG_OVERLAPPED)
+ * Return a pollable file descriptor struct, or INVALID_WINFD on error
+ *
+ * Note that the fd returned by this function is a per-transfer fd, rather
+ * than a per-session fd and cannot be used for anything else but our
+ * custom functions (the fd itself points to the NUL: device)
+ * if you plan to do R/W on the same handle, you MUST create 2 fds: one for
+ * read and one for write. Using a single R/W fd is unsupported and will
+ * produce unexpected results
+ */
+struct winfd usbi_create_fd(HANDLE handle, int access_mode)
+{
+ int i, fd;
+ struct winfd wfd = INVALID_WINFD;
+ OVERLAPPED* overlapped = NULL;
+
+ CHECK_INIT_POLLING;
+
+ if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) {
+ return INVALID_WINFD;
+ }
+
+ if ((access_mode != _O_RDONLY) && (access_mode != _O_WRONLY)) {
+ usbi_warn(NULL, "only one of _O_RDONLY or _O_WRONLY are supported.\n"
+ "If you want to poll for R/W simultaneously, create multiple fds from the same handle.");
+ return INVALID_WINFD;
+ }
+ if (access_mode == _O_RDONLY) {
+ wfd.rw = RW_READ;
+ } else {
+ wfd.rw = RW_WRITE;
+ }
+
+ // Ensure that we get a non system conflicting unique fd, using
+ // the same fd attribution system as the pipe ends
+ fd = _open(NUL_DEVICE, _O_WRONLY);
+ if (fd < 0) {
+ return INVALID_WINFD;
+ }
+
+ overlapped = create_overlapped();
+ if(overlapped == NULL) {
+ _close(fd);
+ return INVALID_WINFD;
+ }
+
+ for (i=0; i<MAX_FDS; i++) {
+ if (poll_fd[i].fd < 0) {
+ EnterCriticalSection(&_poll_fd[i].mutex);
+ // fd might have been removed before we got to critical
+ if (poll_fd[i].fd >= 0) {
+ LeaveCriticalSection(&_poll_fd[i].mutex);
+ continue;
+ }
+ wfd.fd = fd;
+ // Attempt to emulate some of the CancelIoEx behaviour on platforms
+ // that don't have it
+ if (!CancelIoEx_Available) {
+ _poll_fd[i].thread_id = GetCurrentThreadId();
+ if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
+ &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
+ usbi_dbg("could not duplicate handle for CancelIo - using original one");
+ wfd.handle = handle;
+ // Make sure we won't close the original handle on fd deletion then
+ _poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
+ } else {
+ _poll_fd[i].original_handle = handle;
+ }
+ } else {
+ wfd.handle = handle;
+ }
+ wfd.overlapped = overlapped;
+ memcpy(&poll_fd[i], &wfd, sizeof(struct winfd));
+ LeaveCriticalSection(&_poll_fd[i].mutex);
+#if defined(DYNAMIC_FDS)
+ usbi_mutex_lock(&new_fd_mutex);
+ new_fd[nb_new_fds++] = overlapped->hEvent;
+ usbi_mutex_unlock(&new_fd_mutex);
+ // Notify poll that fds have been updated
+ SetEvent(fd_update);
+#endif
+ return wfd;
+ }
+ }
+ free_overlapped(overlapped);
+ _close(fd);
+ return INVALID_WINFD;
+}
+
+void _free_index(int _index)
+{
+ // Cancel any async IO (Don't care about the validity of our handles for this)
+ cancel_io(_index);
+ // close fake handle for devices
+ if ( (poll_fd[_index].handle != INVALID_HANDLE_VALUE) && (poll_fd[_index].handle != 0)
+ && (GetFileType(poll_fd[_index].handle) == FILE_TYPE_UNKNOWN) ) {
+ _close(poll_fd[_index].fd);
+ }
+ // close the duplicate handle (if we have an actual duplicate)
+ if (!CancelIoEx_Available) {
+ if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(poll_fd[_index].handle);
+ }
+ _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE;
+ _poll_fd[_index].thread_id = 0;
+ }
+ free_overlapped(poll_fd[_index].overlapped);
+ poll_fd[_index] = INVALID_WINFD;
+}
+
+/*
+ * Release a pollable file descriptor.
+ *
+ * Note that the associated Windows handle is not closed by this call
+ */
+void usbi_free_fd(int fd)
+{
+ int _index;
+
+ CHECK_INIT_POLLING;
+
+ _index = _fd_to_index_and_lock(fd);
+ if (_index < 0) {
+ return;
+ }
+ _free_index(_index);
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
+}
+
+/*
+ * The functions below perform various conversions between fd, handle and OVERLAPPED
+ */
+struct winfd fd_to_winfd(int fd)
+{
+ int i;
+ struct winfd wfd;
+
+ CHECK_INIT_POLLING;
+
+ if (fd <= 0)
+ return INVALID_WINFD;
+
+ for (i=0; i<MAX_FDS; i++) {
+ if (poll_fd[i].fd == fd) {
+ EnterCriticalSection(&_poll_fd[i].mutex);
+ // fd might have been deleted before we got to critical
+ if (poll_fd[i].fd != fd) {
+ LeaveCriticalSection(&_poll_fd[i].mutex);
+ continue;
+ }
+ memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
+ LeaveCriticalSection(&_poll_fd[i].mutex);
+ return wfd;
+ }
+ }
+ return INVALID_WINFD;
+}
+
+struct winfd handle_to_winfd(HANDLE handle)
+{
+ int i;
+ struct winfd wfd;
+
+ CHECK_INIT_POLLING;
+
+ if ((handle == 0) || (handle == INVALID_HANDLE_VALUE))
+ return INVALID_WINFD;
+
+ for (i=0; i<MAX_FDS; i++) {
+ if (poll_fd[i].handle == handle) {
+ EnterCriticalSection(&_poll_fd[i].mutex);
+ // fd might have been deleted before we got to critical
+ if (poll_fd[i].handle != handle) {
+ LeaveCriticalSection(&_poll_fd[i].mutex);
+ continue;
+ }
+ memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
+ LeaveCriticalSection(&_poll_fd[i].mutex);
+ return wfd;
+ }
+ }
+ return INVALID_WINFD;
+}
+
+struct winfd overlapped_to_winfd(OVERLAPPED* overlapped)
+{
+ int i;
+ struct winfd wfd;
+
+ CHECK_INIT_POLLING;
+
+ if (overlapped == NULL)
+ return INVALID_WINFD;
+
+ for (i=0; i<MAX_FDS; i++) {
+ if (poll_fd[i].overlapped == overlapped) {
+ EnterCriticalSection(&_poll_fd[i].mutex);
+ // fd might have been deleted before we got to critical
+ if (poll_fd[i].overlapped != overlapped) {
+ LeaveCriticalSection(&_poll_fd[i].mutex);
+ continue;
+ }
+ memcpy(&wfd, &poll_fd[i], sizeof(struct winfd));
+ LeaveCriticalSection(&_poll_fd[i].mutex);
+ return wfd;
+ }
+ }
+ return INVALID_WINFD;
+}
+
+/*
+ * POSIX poll equivalent, using Windows OVERLAPPED
+ * Currently, this function only accepts one of POLLIN or POLLOUT per fd
+ * (but you can create multiple fds from the same handle for read and write)
+ */
+int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout)
+{
+ unsigned i;
+ int _index, object_index, triggered;
+ HANDLE *handles_to_wait_on;
+ int *handle_to_index;
+ DWORD nb_handles_to_wait_on = 0;
+ DWORD ret;
+
+#if defined(DYNAMIC_FDS)
+ DWORD nb_extra_handles = 0;
+ unsigned j;
+
+ // To address the possibility of missing new fds between the time the new
+ // pollable fd set is assembled, and the ResetEvent() call below, an
+ // additional new_fd[] HANDLE table is used for any new fd that was created
+ // since the last call to poll (see below)
+ ResetEvent(fd_update);
+
+ // At this stage, any new fd creation will be detected through the fd_update
+ // event notification, and any previous creation that we may have missed
+ // will be picked up through the existing new_fd[] table.
+#endif
+
+ CHECK_INIT_POLLING;
+
+ triggered = 0;
+ handles_to_wait_on = malloc((nfds+1)*sizeof(HANDLE)); // +1 for fd_update
+ handle_to_index = malloc(nfds*sizeof(int));
+ if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) {
+ errno = ENOMEM;
+ triggered = -1;
+ goto poll_exit;
+ }
+
+ for (i = 0; i < nfds; ++i) {
+ fds[i].revents = 0;
+
+ // Only one of POLLIN or POLLOUT can be selected with this version of poll (not both)
+ if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) {
+ fds[i].revents |= POLLERR;
+ errno = EACCES;
+ usbi_warn(NULL, "unsupported set of events");
+ triggered = -1;
+ goto poll_exit;
+ }
+
+ _index = _fd_to_index_and_lock(fds[i].fd);
+ poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[_index].fd, poll_fd[_index].overlapped, fds[i].events);
+
+ if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE)
+ || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) {
+ fds[i].revents |= POLLNVAL | POLLERR;
+ errno = EBADF;
+ if (_index >= 0) {
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
+ }
+ usbi_warn(NULL, "invalid fd");
+ triggered = -1;
+ goto poll_exit;
+ }
+
+ // IN or OUT must match our fd direction
+ if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) {
+ fds[i].revents |= POLLNVAL | POLLERR;
+ errno = EBADF;
+ usbi_warn(NULL, "attempted POLLIN on fd without READ access");
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
+ triggered = -1;
+ goto poll_exit;
+ }
+
+ if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) {
+ fds[i].revents |= POLLNVAL | POLLERR;
+ errno = EBADF;
+ usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access");
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
+ triggered = -1;
+ goto poll_exit;
+ }
+
+ // The following macro only works if overlapped I/O was reported pending
+ if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped))
+ || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) {
+ poll_dbg(" completed");
+ // checks above should ensure this works:
+ fds[i].revents = fds[i].events;
+ triggered++;
+ } else {
+ handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent;
+ handle_to_index[nb_handles_to_wait_on] = i;
+#if defined(DYNAMIC_FDS)
+ // If this fd from the poll set is also part of the new_fd event handle table, remove it
+ usbi_mutex_lock(&new_fd_mutex);
+ for (j=0; j<nb_new_fds; j++) {
+ if (handles_to_wait_on[nb_handles_to_wait_on] == new_fd[j]) {
+ new_fd[j] = INVALID_HANDLE_VALUE;
+ break;
+ }
+ }
+ usbi_mutex_unlock(&new_fd_mutex);
+#endif
+ nb_handles_to_wait_on++;
+ }
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
+ }
+#if defined(DYNAMIC_FDS)
+ // At this stage, new_fd[] should only contain events from fds that
+ // have been added since the last call to poll, but are not (yet) part
+ // of the pollable fd set. Typically, these would be from fds that have
+ // been created between the construction of the fd set and the calling
+ // of poll.
+ // Event if we won't be able to return usable poll data on these events,
+ // make sure we monitor them to return an EINTR code
+ usbi_mutex_lock(&new_fd_mutex); // We could probably do without
+ for (i=0; i<nb_new_fds; i++) {
+ if (new_fd[i] != INVALID_HANDLE_VALUE) {
+ handles_to_wait_on[nb_handles_to_wait_on++] = new_fd[i];
+ nb_extra_handles++;
+ }
+ }
+ usbi_mutex_unlock(&new_fd_mutex);
+ poll_dbg("dynamic_fds: added %d extra handles", nb_extra_handles);
+#endif
+
+ // If nothing was triggered, wait on all fds that require it
+ if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) {
+#if defined(DYNAMIC_FDS)
+ // Register for fd update notifications
+ handles_to_wait_on[nb_handles_to_wait_on++] = fd_update;
+ nb_extra_handles++;
+#endif
+ if (timeout < 0) {
+ poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on);
+ } else {
+ poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on);
+ }
+ ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on,
+ FALSE, (timeout<0)?INFINITE:(DWORD)timeout);
+ object_index = ret-WAIT_OBJECT_0;
+ if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) {
+#if defined(DYNAMIC_FDS)
+ if ((DWORD)object_index >= (nb_handles_to_wait_on-nb_extra_handles)) {
+ // Detected fd update => flag a poll interruption
+ if ((DWORD)object_index == (nb_handles_to_wait_on-1))
+ poll_dbg(" dynamic_fds: fd_update event");
+ else
+ poll_dbg(" dynamic_fds: new fd I/O event");
+ errno = EINTR;
+ triggered = -1;
+ goto poll_exit;
+ }
+#endif
+ poll_dbg(" completed after wait");
+ i = handle_to_index[object_index];
+ _index = _fd_to_index_and_lock(fds[i].fd);
+ fds[i].revents = fds[i].events;
+ triggered++;
+ if (_index >= 0) {
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
+ }
+ } else if (ret == WAIT_TIMEOUT) {
+ poll_dbg(" timed out");
+ triggered = 0; // 0 = timeout
+ } else {
+ errno = EIO;
+ triggered = -1; // error
+ }
+ }
+
+poll_exit:
+ if (handles_to_wait_on != NULL) {
+ free(handles_to_wait_on);
+ }
+ if (handle_to_index != NULL) {
+ free(handle_to_index);
+ }
+#if defined(DYNAMIC_FDS)
+ usbi_mutex_lock(&new_fd_mutex);
+ nb_new_fds = 0;
+ usbi_mutex_unlock(&new_fd_mutex);
+#endif
+ return triggered;
+}
+
+/*
+ * close a fake pipe fd
+ */
+int usbi_close(int fd)
+{
+ int _index;
+ int r = -1;
+
+ CHECK_INIT_POLLING;
+
+ _index = _fd_to_index_and_lock(fd);
+
+ if (_index < 0) {
+ errno = EBADF;
+ } else {
+ if (poll_fd[_index].overlapped != NULL) {
+ // Must be a different event for each end of the pipe
+ CloseHandle(poll_fd[_index].overlapped->hEvent);
+ free(poll_fd[_index].overlapped);
+ }
+ r = _close(poll_fd[_index].fd);
+ if (r != 0) {
+ errno = EIO;
+ }
+ poll_fd[_index] = INVALID_WINFD;
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
+ }
+ return r;
+}
+
+/*
+ * synchronous write for fake "pipe" signaling
+ */
+ssize_t usbi_write(int fd, const void *buf, size_t count)
+{
+ int _index;
+
+ CHECK_INIT_POLLING;
+
+ if (count != sizeof(unsigned char)) {
+ usbi_err(NULL, "this function should only used for signaling");
+ return -1;
+ }
+
+ _index = _fd_to_index_and_lock(fd);
+
+ if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) {
+ errno = EBADF;
+ if (_index >= 0) {
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
+ }
+ return -1;
+ }
+
+ poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
+ SetEvent(poll_fd[_index].overlapped->hEvent);
+ poll_fd[_index].overlapped->Internal = STATUS_WAIT_0;
+ // If two threads write on the pipe at the same time, we need to
+ // process two separate reads => use the overlapped as a counter
+ poll_fd[_index].overlapped->InternalHigh++;
+
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
+ return sizeof(unsigned char);
+}
+
+/*
+ * synchronous read for fake "pipe" signaling
+ */
+ssize_t usbi_read(int fd, void *buf, size_t count)
+{
+ int _index;
+ ssize_t r = -1;
+
+ CHECK_INIT_POLLING;
+
+ if (count != sizeof(unsigned char)) {
+ usbi_err(NULL, "this function should only used for signaling");
+ return -1;
+ }
+
+ _index = _fd_to_index_and_lock(fd);
+
+ if (_index < 0) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) {
+ usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError());
+ errno = EIO;
+ goto out;
+ }
+
+ poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId());
+ poll_fd[_index].overlapped->InternalHigh--;
+ // Don't reset unless we don't have any more events to process
+ if (poll_fd[_index].overlapped->InternalHigh <= 0) {
+ ResetEvent(poll_fd[_index].overlapped->hEvent);
+ poll_fd[_index].overlapped->Internal = STATUS_PENDING;
+ }
+
+ r = sizeof(unsigned char);
+
+out:
+ LeaveCriticalSection(&_poll_fd[_index].mutex);
+ return r;
+}
diff --git a/libusb-1.0/libusb/os/poll_windows.h b/libusb-1.0/libusb/os/poll_windows.h
new file mode 100644
index 0000000..36e3915
--- /dev/null
+++ b/libusb-1.0/libusb/os/poll_windows.h
@@ -0,0 +1,122 @@
+/*
+ * Windows compat: POSIX compatibility wrapper
+ * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com>
+ * With contributions from Michael Plante, Orin Eman et al.
+ * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#pragma once
+
+#if defined(_MSC_VER)
+// disable /W4 MSVC warnings that are benign
+#pragma warning(disable:4127) // conditional expression is constant
+#endif
+
+// Uncomment to have poll return with EINTR as soon as a new transfer (fd) is added
+// This should result in a LIBUSB_ERROR_INTERRUPTED being returned by libusb calls,
+// which should give the app an opportunity to resubmit a new fd set.
+//#define DYNAMIC_FDS
+
+// Handle synchronous completion through the overlapped structure
+#if !defined(STATUS_REPARSE) // reuse the REPARSE status code
+#define STATUS_REPARSE ((LONG)0x00000104L)
+#endif
+#define STATUS_COMPLETED_SYNCHRONOUSLY STATUS_REPARSE
+#define HasOverlappedIoCompletedSync(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY)
+
+#define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2)
+
+enum windows_version {
+ WINDOWS_UNSUPPORTED,
+ WINDOWS_XP,
+ WINDOWS_2003, // also includes XP 64
+ WINDOWS_VISTA_AND_LATER,
+};
+extern enum windows_version windows_version;
+
+#define MAX_FDS 256
+
+#define POLLIN 0x0001 /* There is data to read */
+#define POLLPRI 0x0002 /* There is urgent data to read */
+#define POLLOUT 0x0004 /* Writing now will not block */
+#define POLLERR 0x0008 /* Error condition */
+#define POLLHUP 0x0010 /* Hung up */
+#define POLLNVAL 0x0020 /* Invalid request: fd not open */
+
+struct pollfd {
+ int fd; /* file descriptor */
+ short events; /* requested events */
+ short revents; /* returned events */
+};
+
+typedef unsigned int nfds_t;
+
+// access modes
+enum rw_type {
+ RW_NONE,
+ RW_READ,
+ RW_WRITE,
+};
+
+// fd struct that can be used for polling on Windows
+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
+ enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH)
+};
+extern const struct winfd INVALID_WINFD;
+
+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);
+void usbi_free_fd(int fd);
+struct winfd fd_to_winfd(int fd);
+struct winfd handle_to_winfd(HANDLE handle);
+struct winfd overlapped_to_winfd(OVERLAPPED* overlapped);
+
+/*
+ * Timeval operations
+ */
+#if defined(DDKBUILD)
+#include <winsock.h> // defines timeval functions on DDK
+#endif
+
+#if !defined(TIMESPEC_TO_TIMEVAL)
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (long)(ts)->tv_sec; \
+ (tv)->tv_usec = (long)(ts)->tv_nsec / 1000; \
+}
+#endif
+#if !defined(timersub)
+#define timersub(a, b, result) \
+do { \
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((result)->tv_usec < 0) { \
+ --(result)->tv_sec; \
+ (result)->tv_usec += 1000000; \
+ } \
+} while (0)
+#endif
+
diff --git a/libusb-1.0/libusb/os/threads_posix.h b/libusb-1.0/libusb/os/threads_posix.h
new file mode 100644
index 0000000..dc558d4
--- /dev/null
+++ b/libusb-1.0/libusb/os/threads_posix.h
@@ -0,0 +1,46 @@
+/*
+ * libusb synchronization using POSIX Threads
+ *
+ * Copyright (C) 2010 Peter Stuge <peter@stuge.se>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LIBUSB_THREADS_POSIX_H__
+#define __LIBUSB_THREADS_POSIX_H__
+
+#include <pthread.h>
+
+#define usbi_mutex_static_t pthread_mutex_t
+#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define usbi_mutex_static_lock pthread_mutex_lock
+#define usbi_mutex_static_unlock pthread_mutex_unlock
+
+#define usbi_mutex_t pthread_mutex_t
+#define usbi_mutex_init pthread_mutex_init
+#define usbi_mutex_lock pthread_mutex_lock
+#define usbi_mutex_unlock pthread_mutex_unlock
+#define usbi_mutex_trylock pthread_mutex_trylock
+#define usbi_mutex_destroy pthread_mutex_destroy
+
+#define usbi_cond_t pthread_cond_t
+#define usbi_cond_init pthread_cond_init
+#define usbi_cond_wait pthread_cond_wait
+#define usbi_cond_timedwait pthread_cond_timedwait
+#define usbi_cond_broadcast pthread_cond_broadcast
+#define usbi_cond_destroy pthread_cond_destroy
+#define usbi_cond_signal pthread_cond_signal
+
+#endif /* __LIBUSB_THREADS_POSIX_H__ */
diff --git a/libusb-1.0/libusb/os/threads_windows.c b/libusb-1.0/libusb/os/threads_windows.c
new file mode 100644
index 0000000..fe84ec0
--- /dev/null
+++ b/libusb-1.0/libusb/os/threads_windows.c
@@ -0,0 +1,221 @@
+/*
+ * libusb synchronization on Microsoft Windows
+ *
+ * Copyright (C) 2010 Michael Plante <michael.plante@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <objbase.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "libusbi.h"
+
+// Workaround for MinGW-w64 multilib bug
+#if defined(_MSC_VER) || defined(_WIN64)
+#define INIT_INTERLOCKEDEXCHANGE
+#define pInterlockedExchange InterlockedExchange
+#else
+static LONG (WINAPI *pInterlockedExchange)(LONG volatile *, LONG) = NULL;
+#define INIT_INTERLOCKEDEXCHANGE if (pInterlockedExchange == NULL) { \
+ pInterlockedExchange = (LONG (WINAPI *)(LONG volatile *, LONG)) \
+ GetProcAddress(GetModuleHandle("KERNEL32"), "InterlockedExchange"); \
+ if (pInterlockedExchange == NULL) return ((errno=ENOENT)); \
+ }
+#endif
+
+int usbi_mutex_init(usbi_mutex_t *mutex,
+ const usbi_mutexattr_t *attr) {
+ if(! mutex) return ((errno=EINVAL));
+ *mutex = CreateMutex(NULL, FALSE, NULL);
+ if(!*mutex) return ((errno=ENOMEM));
+ return 0;
+}
+int usbi_mutex_destroy(usbi_mutex_t *mutex) {
+ // It is not clear if CloseHandle failure is due to failure to unlock.
+ // If so, this should be errno=EBUSY.
+ if(!mutex || !CloseHandle(*mutex)) return ((errno=EINVAL));
+ *mutex = NULL;
+ return 0;
+}
+int usbi_mutex_trylock(usbi_mutex_t *mutex) {
+ DWORD result;
+ if(!mutex) return ((errno=EINVAL));
+ result = WaitForSingleObject(*mutex, 0);
+ if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED)
+ return 0; // acquired (ToDo: check that abandoned is ok)
+ if(result == WAIT_TIMEOUT)
+ return ((errno=EBUSY));
+ return ((errno=EINVAL)); // don't know how this would happen
+ // so don't know proper errno
+}
+int usbi_mutex_lock(usbi_mutex_t *mutex) {
+ DWORD result;
+ if(!mutex) return ((errno=EINVAL));
+ result = WaitForSingleObject(*mutex, INFINITE);
+ if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED)
+ return 0; // acquired (ToDo: check that abandoned is ok)
+ return ((errno=EINVAL)); // don't know how this would happen
+ // so don't know proper errno
+}
+int usbi_mutex_unlock(usbi_mutex_t *mutex) {
+ if(!mutex) return ((errno=EINVAL));
+ if(!ReleaseMutex(*mutex)) return ((errno=EPERM ));
+ return 0;
+}
+
+int usbi_mutex_static_lock(usbi_mutex_static_t *mutex) {
+ if(!mutex) return ((errno=EINVAL));
+ INIT_INTERLOCKEDEXCHANGE;
+ while (pInterlockedExchange((LONG *)mutex, 1) == 1) {
+ SleepEx(0, TRUE);
+ }
+ return 0;
+}
+int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) {
+ if(!mutex) return ((errno=EINVAL));
+ *mutex = 0;
+ return 0;
+}
+
+
+
+int usbi_cond_init(usbi_cond_t *cond,
+ const usbi_condattr_t *attr) {
+ if(!cond) return ((errno=EINVAL));
+ list_init(&cond->waiters );
+ list_init(&cond->not_waiting);
+ return 0;
+}
+int usbi_cond_destroy(usbi_cond_t *cond) {
+ // This assumes no one is using this anymore. The check MAY NOT BE safe.
+ struct usbi_cond_perthread *pos, *prev_pos = NULL;
+ if(!cond) return ((errno=EINVAL));
+ if(!list_empty(&cond->waiters)) return ((errno=EBUSY )); // (!see above!)
+ list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) {
+ free(prev_pos);
+ list_del(&pos->list);
+ prev_pos = pos;
+ }
+ free(prev_pos);
+ prev_pos = pos = NULL;
+
+ return 0;
+}
+
+int usbi_cond_broadcast(usbi_cond_t *cond) {
+ // Assumes mutex is locked; this is not in keeping with POSIX spec, but
+ // libusb does this anyway, so we simplify by not adding more sync
+ // primitives to the CV definition!
+ int fail = 0;
+ struct usbi_cond_perthread *pos;
+ if(!cond) return ((errno=EINVAL));
+ list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread) {
+ if(!SetEvent(pos->event))
+ fail = 1;
+ }
+ // The wait function will remove its respective item from the list.
+ return fail ? ((errno=EINVAL)) : 0;
+}
+int usbi_cond_signal(usbi_cond_t *cond) {
+ // Assumes mutex is locked; this is not in keeping with POSIX spec, but
+ // libusb does this anyway, so we simplify by not adding more sync
+ // primitives to the CV definition!
+ struct usbi_cond_perthread *pos;
+ if(!cond) return ((errno=EINVAL));
+ if(list_empty(&cond->waiters)) return 0; // no one to wakeup.
+ pos = list_entry(&cond->waiters.next, struct usbi_cond_perthread, list);
+ // The wait function will remove its respective item from the list.
+ return SetEvent(pos->event) ? 0 : ((errno=EINVAL));
+}
+static int __inline usbi_cond_intwait(usbi_cond_t *cond,
+ usbi_mutex_t *mutex,
+ DWORD timeout_ms) {
+ struct usbi_cond_perthread *pos;
+ int found = 0, r;
+ DWORD r2,tid = GetCurrentThreadId();
+ if(!cond || !mutex) return ((errno=EINVAL));
+ list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) {
+ if(tid == pos->tid) {
+ found = 1;
+ break;
+ }
+ }
+ if(!found) {
+ pos = malloc(sizeof(struct usbi_cond_perthread));
+ if(!pos) return ((errno=ENOMEM)); // This errno is not POSIX-allowed.
+ pos->tid = tid;
+ pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset.
+ if(!pos->event) {
+ free(pos);
+ return ((errno=ENOMEM));
+ }
+ list_add(&pos->list, &cond->not_waiting);
+ }
+
+ list_del(&pos->list); // remove from not_waiting list.
+ list_add(&pos->list, &cond->waiters);
+
+ r = usbi_mutex_unlock(mutex);
+ if(r) return r;
+ r2 = WaitForSingleObject(pos->event, timeout_ms);
+ r = usbi_mutex_lock(mutex);
+ if(r) return r;
+
+ list_del(&pos->list);
+ list_add(&pos->list, &cond->not_waiting);
+
+ if(r2 == WAIT_TIMEOUT) return ((errno=ETIMEDOUT));
+
+ return 0;
+}
+// N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot!
+int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) {
+ return usbi_cond_intwait(cond, mutex, INFINITE);
+}
+int usbi_cond_timedwait(usbi_cond_t *cond,
+ usbi_mutex_t *mutex,
+ const struct timespec *abstime) {
+ FILETIME filetime;
+ ULARGE_INTEGER rtime;
+ struct timeval targ_time, cur_time, delta_time;
+ struct timespec cur_time_ns;
+ DWORD millis;
+ extern const uint64_t epoch_time;
+
+ GetSystemTimeAsFileTime(&filetime);
+ rtime.LowPart = filetime.dwLowDateTime;
+ rtime.HighPart = filetime.dwHighDateTime;
+ rtime.QuadPart -= epoch_time;
+ cur_time_ns.tv_sec = (long)(rtime.QuadPart / 10000000);
+ cur_time_ns.tv_nsec = (long)((rtime.QuadPart % 10000000)*100);
+ TIMESPEC_TO_TIMEVAL(&cur_time, &cur_time_ns);
+
+ TIMESPEC_TO_TIMEVAL(&targ_time, abstime);
+ timersub(&targ_time, &cur_time, &delta_time);
+ if(delta_time.tv_sec < 0) // abstime already passed?
+ millis = 0;
+ else {
+ millis = delta_time.tv_usec/1000;
+ millis += delta_time.tv_sec *1000;
+ if (delta_time.tv_usec % 1000) // round up to next millisecond
+ millis++;
+ }
+
+ return usbi_cond_intwait(cond, mutex, millis);
+}
+
diff --git a/libusb-1.0/libusb/os/threads_windows.h b/libusb-1.0/libusb/os/threads_windows.h
new file mode 100644
index 0000000..2cd1867
--- /dev/null
+++ b/libusb-1.0/libusb/os/threads_windows.h
@@ -0,0 +1,84 @@
+/*
+ * libusb synchronization on Microsoft Windows
+ *
+ * Copyright (C) 2010 Michael Plante <michael.plante@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LIBUSB_THREADS_WINDOWS_H__
+#define __LIBUSB_THREADS_WINDOWS_H__
+
+#define usbi_mutex_static_t volatile LONG
+#define USBI_MUTEX_INITIALIZER 0
+
+#define usbi_mutex_t HANDLE
+
+struct usbi_cond_perthread {
+ struct list_head list;
+ DWORD tid;
+ HANDLE event;
+};
+struct usbi_cond_t_ {
+ // Every time a thread touches the CV, it winds up in one of these lists.
+ // It stays there until the CV is destroyed, even if the thread
+ // terminates.
+ struct list_head waiters;
+ struct list_head not_waiting;
+};
+typedef struct usbi_cond_t_ usbi_cond_t;
+
+// We *were* getting timespec from pthread.h:
+#if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED))
+#define HAVE_STRUCT_TIMESPEC 1
+#define _TIMESPEC_DEFINED 1
+struct timespec {
+ long tv_sec;
+ long tv_nsec;
+};
+#endif /* HAVE_STRUCT_TIMESPEC | _TIMESPEC_DEFINED */
+
+// We *were* getting ETIMEDOUT from pthread.h:
+#ifndef ETIMEDOUT
+# define ETIMEDOUT 10060 /* This is the value in winsock.h. */
+#endif
+
+#define usbi_mutexattr_t void
+#define usbi_condattr_t void
+
+
+int usbi_mutex_static_lock(usbi_mutex_static_t *mutex);
+int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex);
+
+
+int usbi_mutex_init(usbi_mutex_t *mutex,
+ const usbi_mutexattr_t *attr);
+int usbi_mutex_lock(usbi_mutex_t *mutex);
+int usbi_mutex_unlock(usbi_mutex_t *mutex);
+int usbi_mutex_trylock(usbi_mutex_t *mutex);
+int usbi_mutex_destroy(usbi_mutex_t *mutex);
+
+int usbi_cond_init(usbi_cond_t *cond,
+ const usbi_condattr_t *attr);
+int usbi_cond_destroy(usbi_cond_t *cond);
+int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex);
+int usbi_cond_timedwait(usbi_cond_t *cond,
+ usbi_mutex_t *mutex,
+ const struct timespec *abstime);
+int usbi_cond_broadcast(usbi_cond_t *cond);
+int usbi_cond_signal(usbi_cond_t *cond);
+
+#endif /* __LIBUSB_THREADS_WINDOWS_H__ */
+
diff --git a/libusb-1.0/libusb/os/windows_usb.c b/libusb-1.0/libusb/os/windows_usb.c
new file mode 100644
index 0000000..6ad6229
--- /dev/null
+++ b/libusb-1.0/libusb/os/windows_usb.c
@@ -0,0 +1,4226 @@
+/*
+ * windows backend for libusb 1.0
+ * Copyright (c) 2009-2010 Pete Batard <pbatard@gmail.com>
+ * With contributions from Michael Plante, Orin Eman et al.
+ * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
+ * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software
+ * Hash table functions adapted from glibc, by Ulrich Drepper et al.
+ * Major code testing contribution by Xiaofan Chen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+// COMPILATION OPTIONS:
+// - Should libusb automatically claim (and release) the interfaces it requires?
+#define AUTO_CLAIM
+// - Forces instant overlapped completion on timeouts: can prevents extensive
+// wait in poll, after a timeout, but might affect subsequent API calls.
+// ***USE AT YOUR OWN RISKS***
+//#define FORCE_INSTANT_TIMEOUTS
+
+// TODO: move all the assertion failures to usbi_err
+
+#include <config.h>
+#include <windows.h>
+#include <setupapi.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <process.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <objbase.h>
+#include <winioctl.h>
+
+#include <libusbi.h>
+#include "poll_windows.h"
+#include "windows_usb.h"
+
+// The following prevents "banned API" errors when using the MS's WDK OACR/Prefast
+#if defined(_PREFAST_)
+#pragma warning(disable:28719)
+#endif
+
+// The 2 macros below are used in conjunction with safe loops.
+#define LOOP_CHECK(fcall) { r=fcall; if (r != LIBUSB_SUCCESS) continue; }
+#define LOOP_BREAK(err) { r=err; continue; }
+
+extern void usbi_fd_notification(struct libusb_context *ctx);
+
+// Helper prototypes
+static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian);
+static int windows_clock_gettime(int clk_id, struct timespec *tp);
+unsigned __stdcall windows_clock_gettime_threaded(void* param);
+// HUB (limited) API prototypes
+static int hub_open(struct libusb_device_handle *dev_handle);
+static void hub_close(struct libusb_device_handle *dev_handle);
+// WinUSB API prototypes
+static int winusb_init(struct libusb_context *ctx);
+static int winusb_exit(void);
+static int winusb_open(struct libusb_device_handle *dev_handle);
+static void winusb_close(struct libusb_device_handle *dev_handle);
+static int winusb_configure_endpoints(struct libusb_device_handle *dev_handle, int iface);
+static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int iface);
+static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface);
+static int winusb_submit_control_transfer(struct usbi_transfer *itransfer);
+static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting);
+static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer);
+static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint);
+static int winusb_abort_transfers(struct usbi_transfer *itransfer);
+static int winusb_abort_control(struct usbi_transfer *itransfer);
+static int winusb_reset_device(struct libusb_device_handle *dev_handle);
+static int winusb_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size);
+// HID API prototypes
+static int hid_init(struct libusb_context *ctx);
+static int hid_exit(void);
+static int hid_open(struct libusb_device_handle *dev_handle);
+static void hid_close(struct libusb_device_handle *dev_handle);
+static int hid_claim_interface(struct libusb_device_handle *dev_handle, int iface);
+static int hid_release_interface(struct libusb_device_handle *dev_handle, int iface);
+static int hid_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting);
+static int hid_submit_control_transfer(struct usbi_transfer *itransfer);
+static int hid_submit_bulk_transfer(struct usbi_transfer *itransfer);
+static int hid_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint);
+static int hid_abort_transfers(struct usbi_transfer *itransfer);
+static int hid_reset_device(struct libusb_device_handle *dev_handle);
+static int hid_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size);
+// Composite API prototypes
+static int composite_init(struct libusb_context *ctx);
+static int composite_exit(void);
+static int composite_open(struct libusb_device_handle *dev_handle);
+static void composite_close(struct libusb_device_handle *dev_handle);
+static int composite_claim_interface(struct libusb_device_handle *dev_handle, int iface);
+static int composite_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting);
+static int composite_release_interface(struct libusb_device_handle *dev_handle, int iface);
+static int composite_submit_control_transfer(struct usbi_transfer *itransfer);
+static int composite_submit_bulk_transfer(struct usbi_transfer *itransfer);
+static int composite_submit_iso_transfer(struct usbi_transfer *itransfer);
+static int composite_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint);
+static int composite_abort_transfers(struct usbi_transfer *itransfer);
+static int composite_abort_control(struct usbi_transfer *itransfer);
+static int composite_reset_device(struct libusb_device_handle *dev_handle);
+static int composite_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size);
+
+// Workaround for MinGW-w64 multilib bug
+#if defined(_MSC_VER) || defined(_WIN64)
+#define INIT_INTERLOCKEDEXCHANGE
+#define INIT_INTERLOCKEDINCREMENT
+#define pInterlockedExchange InterlockedExchange
+#define pInterlockedIncrement InterlockedIncrement
+#else
+static LONG (WINAPI *pInterlockedExchange)(LONG volatile *, LONG) = NULL;
+#define INIT_INTERLOCKEDEXCHANGE if (pInterlockedExchange == NULL) { \
+ pInterlockedExchange = (LONG (WINAPI *)(LONG volatile *, LONG)) \
+ GetProcAddress(GetModuleHandle("KERNEL32"), "InterlockedExchange"); \
+ if (pInterlockedExchange == NULL) { \
+ usbi_err(NULL, "InterlockedExchange is unavailable"); \
+ return 1; \
+ } \
+}
+static LONG (WINAPI *pInterlockedIncrement)(LONG volatile *) = NULL;
+#define INIT_INTERLOCKEDINCREMENT if (pInterlockedIncrement == NULL) { \
+ pInterlockedIncrement = (LONG (WINAPI *)(LONG volatile *)) \
+ GetProcAddress(GetModuleHandle("KERNEL32"), "InterlockedIncrement");\
+ if (pInterlockedIncrement == NULL) { \
+ usbi_err(NULL, "IInterlockedIncrement is unavailable"); \
+ return LIBUSB_ERROR_NOT_FOUND; \
+ } \
+}
+#endif
+
+// Global variables
+uint64_t hires_frequency, hires_ticks_to_ps;
+const uint64_t epoch_time = UINT64_C(116444736000000000); // 1970.01.01 00:00:000 in MS Filetime
+enum windows_version windows_version = WINDOWS_UNSUPPORTED;
+// Concurrency
+static int concurrent_usage = -1;
+#if defined(AUTO_CLAIM)
+usbi_mutex_t autoclaim_lock;
+#endif
+// Timer thread
+// NB: index 0 is for monotonic and 1 is for the thread exit event
+HANDLE timer_thread = NULL;
+HANDLE timer_mutex = NULL;
+struct timespec timer_tp;
+volatile LONG request_count[2] = {0, 1}; // last one must be > 0
+HANDLE timer_request[2] = { NULL, NULL };
+HANDLE timer_response = NULL;
+// API globals
+bool api_winusb_available = false;
+#define CHECK_WINUSB_AVAILABLE do { if (!api_winusb_available) return LIBUSB_ERROR_ACCESS; } while (0)
+bool api_hid_available = false;
+#define CHECK_HID_AVAILABLE do { if (!api_hid_available) return LIBUSB_ERROR_ACCESS; } while (0)
+
+static inline BOOLEAN guid_eq(const GUID *guid1, const GUID *guid2) {
+ if ((guid1 != NULL) && (guid2 != NULL)) {
+ return (memcmp(guid1, guid2, sizeof(GUID)) == 0);
+ }
+ return false;
+}
+
+#if defined(ENABLE_DEBUG_LOGGING) || defined(INCLUDE_DEBUG_LOGGING)
+static char* guid_to_string(const GUID* guid)
+{
+ static char guid_string[MAX_GUID_STRING_LENGTH];
+
+ if (guid == NULL) return NULL;
+ sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+ (unsigned int)guid->Data1, guid->Data2, guid->Data3,
+ guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
+ guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
+ return guid_string;
+}
+#endif
+
+/*
+ * Converts a windows error to human readable string
+ * uses retval as errorcode, or, if 0, use GetLastError()
+ */
+static char *windows_error_str(uint32_t retval)
+{
+static char err_string[ERR_BUFFER_SIZE];
+
+ DWORD size;
+ size_t i;
+ uint32_t error_code, format_error;
+
+ error_code = retval?retval:GetLastError();
+
+ safe_sprintf(err_string, ERR_BUFFER_SIZE, "[%d] ", error_code);
+
+ size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &err_string[safe_strlen(err_string)],
+ ERR_BUFFER_SIZE - (DWORD)safe_strlen(err_string), NULL);
+ if (size == 0) {
+ format_error = GetLastError();
+ if (format_error)
+ safe_sprintf(err_string, ERR_BUFFER_SIZE,
+ "Windows error code %u (FormatMessage error code %u)", error_code, format_error);
+ else
+ safe_sprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", error_code);
+ } else {
+ // Remove CR/LF terminators
+ for (i=safe_strlen(err_string)-1; ((err_string[i]==0x0A) || (err_string[i]==0x0D)); i--) {
+ err_string[i] = 0;
+ }
+ }
+ return err_string;
+}
+
+/*
+ * Sanitize Microsoft's paths: convert to uppercase, add prefix and fix backslashes.
+ * Return an allocated sanitized string or NULL on error.
+ */
+static char* sanitize_path(const char* path)
+{
+ const char root_prefix[] = "\\\\.\\";
+ size_t j, size, root_size;
+ char* ret_path = NULL;
+ size_t add_root = 0;
+
+ if (path == NULL)
+ return NULL;
+
+ size = safe_strlen(path)+1;
+ root_size = sizeof(root_prefix)-1;
+
+ // Microsoft indiscriminatly uses '\\?\', '\\.\', '##?#" or "##.#" for root prefixes.
+ if (!((size > 3) && (((path[0] == '\\') && (path[1] == '\\') && (path[3] == '\\')) ||
+ ((path[0] == '#') && (path[1] == '#') && (path[3] == '#'))))) {
+ add_root = root_size;
+ size += add_root;
+ }
+
+ if ((ret_path = (char*)calloc(size, 1)) == NULL)
+ return NULL;
+
+ safe_strcpy(&ret_path[add_root], size-add_root, path);
+
+ // Ensure consistancy with root prefix
+ for (j=0; j<root_size; j++)
+ ret_path[j] = root_prefix[j];
+
+ // Same goes for '\' and '#' after the root prefix. Ensure '#' is used
+ for(j=root_size; j<size; j++) {
+ ret_path[j] = (char)toupper((int)ret_path[j]); // Fix case too
+ if (ret_path[j] == '\\')
+ ret_path[j] = '#';
+ }
+
+ return ret_path;
+}
+
+/*
+ * Cfgmgr32, OLE32 and SetupAPI DLL functions
+ */
+static int init_dlls(void)
+{
+ DLL_LOAD(Cfgmgr32.dll, CM_Get_Parent, TRUE);
+ DLL_LOAD(Cfgmgr32.dll, CM_Get_Child, TRUE);
+ DLL_LOAD(Cfgmgr32.dll, CM_Get_Sibling, TRUE);
+ DLL_LOAD(Cfgmgr32.dll, CM_Get_Device_IDA, TRUE);
+ // Prefixed to avoid conflict with header files
+ DLL_LOAD_PREFIXED(OLE32.dll, p, CLSIDFromString, TRUE);
+ DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiGetClassDevsA, TRUE);
+ DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiEnumDeviceInfo, TRUE);
+ DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiEnumDeviceInterfaces, TRUE);
+ DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiGetDeviceInterfaceDetailA, TRUE);
+ DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiDestroyDeviceInfoList, TRUE);
+ DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiOpenDevRegKey, TRUE);
+ DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiGetDeviceRegistryPropertyA, TRUE);
+ DLL_LOAD_PREFIXED(AdvAPI32.dll, p, RegQueryValueExW, TRUE);
+ DLL_LOAD_PREFIXED(AdvAPI32.dll, p, RegCloseKey, TRUE);
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * enumerate interfaces for the whole USB class
+ *
+ * Parameters:
+ * dev_info: a pointer to a dev_info list
+ * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed)
+ * guid: the GUID for which to retrieve interface details
+ * index: zero based index of the interface in the device info list
+ *
+ * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA
+ * structure returned and call this function repeatedly using the same guid (with an
+ * incremented index starting at zero) until all interfaces have been returned.
+ */
+bool get_devinfo_data(struct libusb_context *ctx,
+ HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, unsigned _index)
+{
+ if (_index <= 0) {
+ *dev_info = pSetupDiGetClassDevsA(NULL, "USB", NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES);
+ if (*dev_info == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+ }
+
+ dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
+ if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) {
+ if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+ usbi_err(ctx, "Could not obtain device info data for index %u: %s",
+ _index, windows_error_str(0));
+ }
+ pSetupDiDestroyDeviceInfoList(*dev_info);
+ *dev_info = INVALID_HANDLE_VALUE;
+ return false;
+ }
+ return true;
+}
+
+/*
+ * enumerate interfaces for a specific GUID
+ *
+ * Parameters:
+ * dev_info: a pointer to a dev_info list
+ * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed)
+ * guid: the GUID for which to retrieve interface details
+ * index: zero based index of the interface in the device info list
+ *
+ * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA
+ * structure returned and call this function repeatedly using the same guid (with an
+ * incremented index starting at zero) until all interfaces have been returned.
+ */
+SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details(struct libusb_context *ctx,
+ HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID* guid, unsigned _index)
+{
+ SP_DEVICE_INTERFACE_DATA dev_interface_data;
+ SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL;
+ DWORD size;
+
+ if (_index <= 0) {
+ *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
+ }
+
+ if (dev_info_data != NULL) {
+ dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
+ if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) {
+ if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+ usbi_err(ctx, "Could not obtain device info data for index %u: %s",
+ _index, windows_error_str(0));
+ }
+ pSetupDiDestroyDeviceInfoList(*dev_info);
+ *dev_info = INVALID_HANDLE_VALUE;
+ return NULL;
+ }
+ }
+
+ dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+ if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, guid, _index, &dev_interface_data)) {
+ if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+ usbi_err(ctx, "Could not obtain interface data for index %u: %s",
+ _index, windows_error_str(0));
+ }
+ pSetupDiDestroyDeviceInfoList(*dev_info);
+ *dev_info = INVALID_HANDLE_VALUE;
+ return NULL;
+ }
+
+ // Read interface data (dummy + actual) to access the device path
+ if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) {
+ // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ usbi_err(ctx, "could not access interface data (dummy) for index %u: %s",
+ _index, windows_error_str(0));
+ goto err_exit;
+ }
+ } else {
+ usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong.");
+ goto err_exit;
+ }
+
+ if ((dev_interface_details = malloc(size)) == NULL) {
+ usbi_err(ctx, "could not allocate interface data for index %u.", _index);
+ goto err_exit;
+ }
+
+ dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
+ if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data,
+ dev_interface_details, size, &size, NULL)) {
+ usbi_err(ctx, "could not access interface data (actual) for index %u: %s",
+ _index, windows_error_str(0));
+ }
+
+ return dev_interface_details;
+
+err_exit:
+ pSetupDiDestroyDeviceInfoList(*dev_info);
+ *dev_info = INVALID_HANDLE_VALUE;
+ return NULL;
+}
+
+/* Hash table functions - modified From glibc 2.3.2:
+ [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
+ [Knuth] The Art of Computer Programming, part 3 (6.4) */
+typedef struct htab_entry {
+ unsigned long used;
+ char* str;
+} htab_entry;
+htab_entry* htab_table = NULL;
+usbi_mutex_t htab_write_mutex = NULL;
+unsigned long htab_size, htab_filled;
+
+/* For the used double hash method the table size has to be a prime. To
+ correct the user given table size we need a prime test. This trivial
+ algorithm is adequate because the code is called only during init and
+ the number is likely to be small */
+static int isprime(unsigned long number)
+{
+ // no even number will be passed
+ unsigned int divider = 3;
+
+ while((divider * divider < number) && (number % divider != 0))
+ divider += 2;
+
+ return (number % divider != 0);
+}
+
+/* Before using the hash table we must allocate memory for it.
+ We allocate one element more as the found prime number says.
+ This is done for more effective indexing as explained in the
+ comment for the hash function. */
+int htab_create(struct libusb_context *ctx, unsigned long nel)
+{
+ if (htab_table != NULL) {
+ usbi_err(ctx, "hash table already allocated");
+ }
+
+ // Create a mutex
+ usbi_mutex_init(&htab_write_mutex, NULL);
+
+ // Change nel to the first prime number not smaller as nel.
+ nel |= 1;
+ while(!isprime(nel))
+ nel += 2;
+
+ htab_size = nel;
+ usbi_dbg("using %d entries hash table", nel);
+ htab_filled = 0;
+
+ // allocate memory and zero out.
+ htab_table = (htab_entry*)calloc(htab_size + 1, sizeof(htab_entry));
+ if (htab_table == NULL) {
+ usbi_err(ctx, "could not allocate space for hash table");
+ return 0;
+ }
+
+ return 1;
+}
+
+/* After using the hash table it has to be destroyed. */
+void htab_destroy(void)
+{
+ size_t i;
+ if (htab_table == NULL) {
+ return;
+ }
+
+ for (i=0; i<htab_size; i++) {
+ if (htab_table[i].used) {
+ safe_free(htab_table[i].str);
+ }
+ }
+ usbi_mutex_destroy(&htab_write_mutex);
+ safe_free(htab_table);
+}
+
+/* This is the search function. It uses double hashing with open addressing.
+ We use an trick to speed up the lookup. The table is created with one
+ more element available. This enables us to use the index zero special.
+ This index will never be used because we store the first hash index in
+ the field used where zero means not used. Every other value means used.
+ The used field can be used as a first fast comparison for equality of
+ the stored and the parameter value. This helps to prevent unnecessary
+ expensive calls of strcmp. */
+unsigned long htab_hash(char* str)
+{
+ unsigned long hval, hval2;
+ unsigned long idx;
+ unsigned long r = 5381;
+ int c;
+ char* sz = str;
+
+ // Compute main hash value (algorithm suggested by Nokia)
+ while ((c = *sz++))
+ r = ((r << 5) + r) + c;
+ if (r == 0)
+ ++r;
+
+ // compute table hash: simply take the modulus
+ hval = r % htab_size;
+ if (hval == 0)
+ ++hval;
+
+ // Try the first index
+ idx = hval;
+
+ if (htab_table[idx].used) {
+ if ( (htab_table[idx].used == hval)
+ && (safe_strcmp(str, htab_table[idx].str) == 0) ) {
+ // existing hash
+ return idx;
+ }
+ usbi_dbg("hash collision ('%s' vs '%s')", str, htab_table[idx].str);
+
+ // Second hash function, as suggested in [Knuth]
+ hval2 = 1 + hval % (htab_size - 2);
+
+ do {
+ // Because size is prime this guarantees to step through all available indexes
+ if (idx <= hval2) {
+ idx = htab_size + idx - hval2;
+ } else {
+ idx -= hval2;
+ }
+
+ // If we visited all entries leave the loop unsuccessfully
+ if (idx == hval) {
+ break;
+ }
+
+ // If entry is found use it.
+ if ( (htab_table[idx].used == hval)
+ && (safe_strcmp(str, htab_table[idx].str) == 0) ) {
+ return idx;
+ }
+ }
+ while (htab_table[idx].used);
+ }
+
+ // Not found => New entry
+
+ // If the table is full return an error
+ if (htab_filled >= htab_size) {
+ usbi_err(NULL, "hash table is full (%d entries)", htab_size);
+ return 0;
+ }
+
+ // Concurrent threads might be storing the same entry at the same time
+ // (eg. "simultaneous" enums from different threads) => use a mutex
+ usbi_mutex_lock(&htab_write_mutex);
+ // Just free any previously allocated string (which should be the same as
+ // new one). The possibility of concurrent threads storing a collision
+ // string (same hash, different string) at the same time is extremely low
+ safe_free(htab_table[idx].str);
+ htab_table[idx].used = hval;
+ htab_table[idx].str = malloc(safe_strlen(str)+1);
+ if (htab_table[idx].str == NULL) {
+ usbi_err(NULL, "could not duplicate string for hash table");
+ usbi_mutex_unlock(&htab_write_mutex);
+ return 0;
+ }
+ memcpy(htab_table[idx].str, str, safe_strlen(str)+1);
+ ++htab_filled;
+ usbi_mutex_unlock(&htab_write_mutex);
+
+ return idx;
+}
+
+/*
+ * Returns the session ID of a device's nth level ancestor
+ */
+static unsigned long get_ancestor_session_id(DWORD devinst, unsigned level)
+{
+ DWORD parent_devinst;
+ unsigned long session_id = 0;
+ char* sanitized_path = NULL;
+ char path[MAX_PATH_LENGTH];
+ unsigned i;
+
+ if (level < 1) return 0;
+ for (i = 0; i<level; i++) {
+ if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS) {
+ return 0;
+ }
+ devinst = parent_devinst;
+ }
+ if (CM_Get_Device_IDA(devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) {
+ return 0;
+ }
+ // Return a special invalid session ID if the GP is not USB (as can be the case for HID)
+ if ((level == 2) && (path[0] != 'U') && (path[1] != 'S') && (path[2] != 'B')) {
+ usbi_dbg("detected non USB parent '%s'", path);
+ return ~0;
+ }
+ // TODO (post hotplug): try without sanitizing
+ sanitized_path = sanitize_path(path);
+ if (sanitized_path == NULL) {
+ return 0;
+ }
+ session_id = htab_hash(sanitized_path);
+ safe_free(sanitized_path);
+ return session_id;
+}
+
+/*
+ * Populate the endpoints addresses of the device_priv interface helper structs
+ */
+static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int iface, int altsetting)
+{
+ int i, r;
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ struct libusb_config_descriptor *conf_desc;
+ const struct libusb_interface_descriptor *if_desc;
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+
+ r = libusb_get_config_descriptor(dev_handle->dev, 0, &conf_desc);
+ if (r != LIBUSB_SUCCESS) {
+ usbi_warn(ctx, "could not read config descriptor: error %d", r);
+ return r;
+ }
+
+ if_desc = &conf_desc->interface[iface].altsetting[altsetting];
+ safe_free(priv->usb_interface[iface].endpoint);
+
+ if (if_desc->bNumEndpoints == 0) {
+ usbi_dbg("no endpoints found for interface %d", iface);
+ return LIBUSB_SUCCESS;
+ }
+
+ priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints);
+ if (priv->usb_interface[iface].endpoint == NULL) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints;
+ for (i=0; i<if_desc->bNumEndpoints; i++) {
+ priv->usb_interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress;
+ usbi_dbg("(re)assigned endpoint %02X to interface %d", priv->usb_interface[iface].endpoint[i], iface);
+ }
+ libusb_free_config_descriptor(conf_desc);
+
+ // Extra init is required for WinUSB endpoints
+ if (priv->apib->id == USB_API_WINUSB) {
+ return winusb_configure_endpoints(dev_handle, iface);
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+// Lookup for a match in the list of API driver names
+bool is_api_driver(char* driver, uint8_t api)
+{
+ uint8_t i;
+ const char sep_str[2] = {LIST_SEPARATOR, 0};
+ char *tok, *tmp_str;
+ size_t len = safe_strlen(driver);
+
+ if (len == 0) return false;
+ tmp_str = calloc(len+1, 1);
+ if (tmp_str == NULL) return false;
+ memcpy(tmp_str, driver, len+1);
+ tok = strtok(tmp_str, sep_str);
+ while (tok != NULL) {
+ for (i=0; i<usb_api_backend[api].nb_driver_names; i++) {
+ if (safe_strcmp(tok, usb_api_backend[api].driver_name_list[i]) == 0) {
+ free(tmp_str);
+ return true;
+ }
+ }
+ tok = strtok(NULL, sep_str);
+ }
+ free (tmp_str);
+ return false;
+}
+
+/*
+ * auto-claiming and auto-release helper functions
+ */
+#if defined(AUTO_CLAIM)
+static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type)
+{
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(
+ transfer->dev_handle);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ int current_interface = *interface_number;
+ int r = LIBUSB_SUCCESS;
+
+ switch(api_type) {
+ case USB_API_WINUSB:
+ case USB_API_HID:
+ break;
+ default:
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ usbi_mutex_lock(&autoclaim_lock);
+ if (current_interface < 0) // No serviceable interface was found
+ {
+ for (current_interface=0; current_interface<USB_MAXINTERFACES; current_interface++) {
+ // Must claim an interface of the same API type
+ if ( (priv->usb_interface[current_interface].apib->id == api_type)
+ && (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS) ) {
+ usbi_dbg("auto-claimed interface %d for control request", current_interface);
+ if (handle_priv->autoclaim_count[current_interface] != 0) {
+ usbi_warn(ctx, "program assertion failed - autoclaim_count was nonzero");
+ }
+ handle_priv->autoclaim_count[current_interface]++;
+ break;
+ }
+ }
+ if (current_interface == USB_MAXINTERFACES) {
+ usbi_err(ctx, "could not auto-claim any interface");
+ r = LIBUSB_ERROR_NOT_FOUND;
+ }
+ } else {
+ // If we have a valid interface that was autoclaimed, we must increment
+ // its autoclaim count so that we can prevent an early release.
+ if (handle_priv->autoclaim_count[current_interface] != 0) {
+ handle_priv->autoclaim_count[current_interface]++;
+ }
+ }
+ usbi_mutex_unlock(&autoclaim_lock);
+
+ *interface_number = current_interface;
+ return r;
+
+}
+
+static void auto_release(struct usbi_transfer *itransfer)
+{
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ libusb_device_handle *dev_handle = transfer->dev_handle;
+ struct windows_device_handle_priv* handle_priv = __device_handle_priv(dev_handle);
+ int r;
+
+ usbi_mutex_lock(&autoclaim_lock);
+ if (handle_priv->autoclaim_count[transfer_priv->interface_number] > 0) {
+ handle_priv->autoclaim_count[transfer_priv->interface_number]--;
+ if (handle_priv->autoclaim_count[transfer_priv->interface_number] == 0) {
+ r = libusb_release_interface(dev_handle, transfer_priv->interface_number);
+ if (r == LIBUSB_SUCCESS) {
+ usbi_dbg("auto-released interface %d", transfer_priv->interface_number);
+ } else {
+ usbi_dbg("failed to auto-release interface %d (%s)",
+ transfer_priv->interface_number, libusb_strerror(r));
+ }
+ }
+ }
+ usbi_mutex_unlock(&autoclaim_lock);
+}
+#endif
+
+
+/*
+ * init: libusb backend init function
+ *
+ * This function enumerates the HCDs (Host Controller Drivers) and populates our private HCD list
+ * In our implementation, we equate Windows' "HCD" to LibUSB's "bus". Note that bus is zero indexed.
+ * HCDs are not expected to change after init (might not hold true for hot pluggable USB PCI card?)
+ */
+static int windows_init(struct libusb_context *ctx)
+{
+ int i, r = LIBUSB_ERROR_OTHER;
+ OSVERSIONINFO os_version;
+ HANDLE semaphore;
+ char sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
+
+ sprintf(sem_name, "libusb_init%08X", (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
+ semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
+ if (semaphore == NULL) {
+ usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ // A successful wait brings our semaphore count to 0 (unsignaled)
+ // => any concurent wait stalls until the semaphore's release
+ if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
+ usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0));
+ CloseHandle(semaphore);
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ // NB: concurrent usage supposes that init calls are equally balanced with
+ // exit calls. If init is called more than exit, we will not exit properly
+ if ( ++concurrent_usage == 0 ) { // First init?
+ // Detect OS version
+ memset(&os_version, 0, sizeof(OSVERSIONINFO));
+ os_version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ windows_version = WINDOWS_UNSUPPORTED;
+ if ((GetVersionEx(&os_version) != 0) && (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
+ if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 1)) {
+ windows_version = WINDOWS_XP;
+ } else if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 2)) {
+ windows_version = WINDOWS_2003; // also includes XP 64
+ } else if (os_version.dwMajorVersion >= 6) {
+ windows_version = WINDOWS_VISTA_AND_LATER;
+ }
+ }
+ if (windows_version == WINDOWS_UNSUPPORTED) {
+ usbi_err(ctx, "This version of Windows is NOT supported");
+ r = LIBUSB_ERROR_NOT_SUPPORTED;
+ goto init_exit;
+ }
+
+#if defined(AUTO_CLAIM)
+ // We need a lock for proper auto-release
+ usbi_mutex_init(&autoclaim_lock, NULL);
+#endif
+
+ // Initialize pollable file descriptors
+ init_polling();
+
+ // Load DLL imports
+ if (init_dlls() != LIBUSB_SUCCESS) {
+ usbi_err(ctx, "could not resolve DLL functions");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ // Initialize the low level APIs (we don't care about errors at this stage)
+ for (i=0; i<USB_API_MAX; i++) {
+ usb_api_backend[i].init(ctx);
+ }
+
+ // Because QueryPerformanceCounter might report different values when
+ // running on different cores, we create a separate thread for the timer
+ // calls, which we glue to the first core always to prevent timing discrepancies.
+ r = LIBUSB_ERROR_NO_MEM;
+ for (i = 0; i < 2; i++) {
+ timer_request[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (timer_request[i] == NULL) {
+ usbi_err(ctx, "could not create timer request event %d - aborting", i);
+ goto init_exit;
+ }
+ }
+ timer_response = CreateSemaphore(NULL, 0, MAX_TIMER_SEMAPHORES, NULL);
+ if (timer_response == NULL) {
+ usbi_err(ctx, "could not create timer response semaphore - aborting");
+ goto init_exit;
+ }
+ timer_mutex = CreateMutex(NULL, FALSE, NULL);
+ if (timer_mutex == NULL) {
+ usbi_err(ctx, "could not create timer mutex - aborting");
+ goto init_exit;
+ }
+ timer_thread = (HANDLE)_beginthreadex(NULL, 0, windows_clock_gettime_threaded, NULL, 0, NULL);
+ if (timer_thread == NULL) {
+ usbi_err(ctx, "Unable to create timer thread - aborting");
+ goto init_exit;
+ }
+ SetThreadAffinityMask(timer_thread, 0);
+
+ // Create a hash table to store session ids. Second parameter is better if prime
+ htab_create(ctx, HTAB_SIZE);
+
+ r = LIBUSB_SUCCESS;
+ }
+
+init_exit: // Holds semaphore here.
+ if(!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
+ if (timer_thread) {
+ SetEvent(timer_request[1]); // actually the signal to quit the thread.
+ if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
+ usbi_warn(ctx, "could not wait for timer thread to quit");
+ TerminateThread(timer_thread, 1); // shouldn't happen, but we're destroying
+ // all objects it might have held anyway.
+ }
+ CloseHandle(timer_thread);
+ timer_thread = NULL;
+ }
+ for (i = 0; i < 2; i++) {
+ if (timer_request[i]) {
+ CloseHandle(timer_request[i]);
+ timer_request[i] = NULL;
+ }
+ }
+ if (timer_response) {
+ CloseHandle(timer_response);
+ timer_response = NULL;
+ }
+ if (timer_mutex) {
+ CloseHandle(timer_mutex);
+ timer_mutex = NULL;
+ }
+ htab_destroy();
+ }
+
+ if (r != LIBUSB_SUCCESS)
+ --concurrent_usage; // Not expected to call libusb_exit if we failed.
+
+ ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
+ CloseHandle(semaphore);
+ return r;
+}
+
+/*
+ * HCD (root) hubs need to have their device descriptor manually populated
+ *
+ * Note that, like Microsoft does in the device manager, we populate the
+ * Vendor and Device ID for HCD hubs with the ones from the PCI HCD device.
+ */
+static int force_hcd_device_descriptor(struct libusb_device *dev)
+{
+ struct windows_device_priv *parent_priv, *priv = __device_priv(dev);
+ struct libusb_context *ctx = DEVICE_CTX(dev);
+ int vid, pid;
+
+ dev->num_configurations = 1;
+ priv->dev_descriptor.bLength = sizeof(USB_DEVICE_DESCRIPTOR);
+ priv->dev_descriptor.bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE;
+ priv->dev_descriptor.bNumConfigurations = 1;
+ priv->active_config = 1;
+
+ if (priv->parent_dev == NULL) {
+ usbi_err(ctx, "program assertion failed - HCD hub has no parent");
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+ parent_priv = __device_priv(priv->parent_dev);
+ if (sscanf(parent_priv->path, "\\\\.\\PCI#VEN_%04x&DEV_%04x%*s", &vid, &pid) == 2) {
+ priv->dev_descriptor.idVendor = (uint16_t)vid;
+ priv->dev_descriptor.idProduct = (uint16_t)pid;
+ } else {
+ usbi_warn(ctx, "could not infer VID/PID of HCD hub from '%s'", parent_priv->path);
+ priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub
+ priv->dev_descriptor.idProduct = 1;
+ }
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * fetch and cache all the config descriptors through I/O
+ */
+static int cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle, char* device_id)
+{
+ DWORD size, ret_size;
+ struct libusb_context *ctx = DEVICE_CTX(dev);
+ struct windows_device_priv *priv = __device_priv(dev);
+ int r;
+ uint8_t i;
+
+ USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request
+ PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request
+ PUSB_CONFIGURATION_DESCRIPTOR cd_data = NULL;
+
+ if (dev->num_configurations == 0)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ priv->config_descriptor = malloc(dev->num_configurations * sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
+ if (priv->config_descriptor == NULL)
+ return LIBUSB_ERROR_NO_MEM;
+ for (i=0; i<dev->num_configurations; i++)
+ priv->config_descriptor[i] = NULL;
+
+ for (i=0, r=LIBUSB_SUCCESS; ; i++)
+ {
+ // safe loop: release all dynamic resources
+ safe_free(cd_buf_actual);
+
+ // safe loop: end of loop condition
+ if ((i >= dev->num_configurations) || (r != LIBUSB_SUCCESS))
+ break;
+
+ size = sizeof(USB_CONFIGURATION_DESCRIPTOR_SHORT);
+ memset(&cd_buf_short, 0, size);
+
+ cd_buf_short.req.ConnectionIndex = (ULONG)priv->port;
+ cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
+ cd_buf_short.req.SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
+ cd_buf_short.req.SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i;
+ cd_buf_short.req.SetupPacket.wIndex = i;
+ cd_buf_short.req.SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST));
+
+ // Dummy call to get the required data size
+ if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &cd_buf_short, size,
+ &cd_buf_short, size, &ret_size, NULL)) {
+ usbi_err(ctx, "could not access configuration descriptor (dummy) for '%s': %s", device_id, windows_error_str(0));
+ LOOP_BREAK(LIBUSB_ERROR_IO);
+ }
+
+ if ((ret_size != size) || (cd_buf_short.data.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))) {
+ usbi_err(ctx, "unexpected configuration descriptor size (dummy) for '%s'.", device_id);
+ LOOP_BREAK(LIBUSB_ERROR_IO);
+ }
+
+ size = sizeof(USB_DESCRIPTOR_REQUEST) + cd_buf_short.data.wTotalLength;
+ if ((cd_buf_actual = (PUSB_DESCRIPTOR_REQUEST)malloc(size)) == NULL) {
+ usbi_err(ctx, "could not allocate configuration descriptor buffer for '%s'.", device_id);
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+ }
+ memset(cd_buf_actual, 0, size);
+
+ // Actual call
+ cd_buf_actual->ConnectionIndex = (ULONG)priv->port;
+ cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
+ cd_buf_actual->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
+ cd_buf_actual->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i;
+ cd_buf_actual->SetupPacket.wIndex = i;
+ cd_buf_actual->SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST));
+
+ if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, cd_buf_actual, size,
+ cd_buf_actual, size, &ret_size, NULL)) {
+ usbi_err(ctx, "could not access configuration descriptor (actual) for '%s': %s", device_id, windows_error_str(0));
+ LOOP_BREAK(LIBUSB_ERROR_IO);
+ }
+
+ cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR*)cd_buf_actual+sizeof(USB_DESCRIPTOR_REQUEST));
+
+ if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.data.wTotalLength)) {
+ usbi_err(ctx, "unexpected configuration descriptor size (actual) for '%s'.", device_id);
+ LOOP_BREAK(LIBUSB_ERROR_IO);
+ }
+
+ if (cd_data->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE) {
+ usbi_err(ctx, "not a configuration descriptor for '%s'", device_id);
+ LOOP_BREAK(LIBUSB_ERROR_IO);
+ }
+
+ usbi_dbg("cached config descriptor %d (bConfigurationValue=%d, %d bytes)",
+ i, cd_data->bConfigurationValue, cd_data->wTotalLength);
+
+ // Cache the descriptor
+ priv->config_descriptor[i] = malloc(cd_data->wTotalLength);
+ if (priv->config_descriptor[i] == NULL)
+ return LIBUSB_ERROR_NO_MEM;
+
+ memcpy(priv->config_descriptor[i], cd_data, cd_data->wTotalLength);
+ }
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * Populate a libusb device structure
+ */
+static int init_device(struct libusb_device* dev, struct libusb_device* parent_dev,
+ uint8_t port_number, char* device_id, DWORD devinst)
+{
+ HANDLE handle;
+ DWORD size;
+ USB_NODE_CONNECTION_INFORMATION conn_info;
+ struct windows_device_priv *priv, *parent_priv;
+ struct libusb_context *ctx = DEVICE_CTX(dev);
+ struct libusb_device* tmp_dev;
+ unsigned i;
+
+ if ((dev == NULL) || (parent_dev == NULL)) {
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+ priv = __device_priv(dev);
+ parent_priv = __device_priv(parent_dev);
+ if (parent_priv->apib->id != USB_API_HUB) {
+ usbi_warn(ctx, "parent for device '%s' is not a hub", device_id);
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ // It is possible for the parent hub not to have been initialized yet
+ // If that's the case, lookup the ancestors to set the bus number
+ if (parent_dev->bus_number == 0) {
+ for (i=2; ; i++) {
+ tmp_dev = usbi_get_device_by_session_id(ctx, get_ancestor_session_id(devinst, i));
+ if (tmp_dev == NULL) break;
+ if (tmp_dev->bus_number != 0) {
+ usbi_dbg("got bus number from ancestor #%d", i);
+ parent_dev->bus_number = tmp_dev->bus_number;
+ break;
+ }
+ }
+ }
+ if (parent_dev->bus_number == 0) {
+ usbi_err(ctx, "program assertion failed: unable to find ancestor bus number for '%s'", device_id);
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+ dev->bus_number = parent_dev->bus_number;
+ priv->port = port_number;
+ priv->depth = parent_priv->depth + 1;
+ priv->parent_dev = parent_dev;
+ memset(&conn_info, 0, sizeof(conn_info));
+
+ if (priv->depth != 0) { // Not a HCD hub
+ handle = CreateFileA(parent_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED, NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ usbi_warn(ctx, "could not open hub %s: %s", parent_priv->path, windows_error_str(0));
+ return LIBUSB_ERROR_ACCESS;
+ }
+ size = sizeof(USB_NODE_CONNECTION_INFORMATION);
+ conn_info.ConnectionIndex = (ULONG)port_number;
+ if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, &conn_info, size,
+ &conn_info, size, &size, NULL)) {
+ usbi_warn(ctx, "could not get node connection information for device '%s': %s",
+ device_id, windows_error_str(0));
+ safe_closehandle(handle);
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+ if (conn_info.ConnectionStatus == NoDeviceConnected) {
+ usbi_err(ctx, "device '%s' is no longer connected!", device_id);
+ safe_closehandle(handle);
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+ dev->device_address = (uint8_t)conn_info.DeviceAddress;
+ memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR));
+ dev->num_configurations = priv->dev_descriptor.bNumConfigurations;
+ priv->active_config = conn_info.CurrentConfigurationValue;
+ usbi_dbg("found %d configurations (active conf: %d)", dev->num_configurations, priv->active_config);
+ // If we can't read the config descriptors, just set the number of confs to zero
+ if (cache_config_descriptors(dev, handle, device_id) != LIBUSB_SUCCESS) {
+ dev->num_configurations = 0;
+ priv->dev_descriptor.bNumConfigurations = 0;
+ }
+ safe_closehandle(handle);
+
+ if (conn_info.DeviceAddress > UINT8_MAX) {
+ usbi_err(ctx, "program assertion failed: device address overflow");
+ }
+ dev->device_address = (uint8_t)conn_info.DeviceAddress;
+ } else {
+ dev->device_address = UINT8_MAX; // Hubs from HCD have a devaddr of 255
+ force_hcd_device_descriptor(dev);
+ }
+
+ usbi_dbg("(bus: %d, addr: %d, depth: %d, port: %d): '%s'",
+ dev->bus_number, dev->device_address, priv->depth, priv->port, device_id);
+
+ return LIBUSB_SUCCESS;
+}
+
+// Returns the api type, or 0 if not found/unsupported
+static uint8_t get_api_type(struct libusb_context *ctx,
+ HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data)
+{
+ // Precedence for filter drivers vs driver is in the order of this array
+ struct driver_lookup lookup[3] = {
+ {"\0\0", SPDRP_SERVICE, "driver"},
+ {"\0\0", SPDRP_UPPERFILTERS, "upper filter driver"},
+ {"\0\0", SPDRP_LOWERFILTERS, "lower filter driver"}
+ };
+ DWORD size, reg_type;
+ unsigned k, l;
+ uint8_t api;
+
+ // Check the service & filter names to know the API we should use
+ for (k=0; k<3; k++) {
+ if (pSetupDiGetDeviceRegistryPropertyA(*dev_info, dev_info_data, lookup[k].reg_prop,
+ &reg_type, (BYTE*)lookup[k].list, MAX_KEY_LENGTH, &size)) {
+ // Turn the REG_SZ SPDRP_SERVICE into REG_MULTI_SZ
+ if (lookup[k].reg_prop == SPDRP_SERVICE) {
+ // our buffers are MAX_KEY_LENGTH+1 so we can overflow if needed
+ lookup[k].list[safe_strlen(lookup[k].list)+1] = 0;
+ }
+ // MULTI_SZ is a pain to work with. Turn it into something much more manageable
+ // NB: none of the driver names we check against contain LIST_SEPARATOR,
+ // (currently ';'), so even if an unsuported one does, it's not an issue
+ for (l=0; (lookup[k].list[l] != 0) || (lookup[k].list[l+1] != 0); l++) {
+ if (lookup[k].list[l] == 0) {
+ lookup[k].list[l] = LIST_SEPARATOR;
+ }
+ }
+ upperize(lookup[k].list);
+ usbi_dbg("%s(s): %s", lookup[k].designation, lookup[k].list);
+ } else {
+ if (GetLastError() != ERROR_INVALID_DATA) {
+ usbi_dbg("could not access %s: %s", lookup[k].designation, windows_error_str(0));
+ }
+ lookup[k].list[0] = 0;
+ }
+ }
+
+ for (api=1; api<USB_API_MAX; api++) {
+ for (k=0; k<3; k++) {
+ if (is_api_driver(lookup[k].list, api)) {
+ usbi_dbg("matched %s name against %s", lookup[k].designation, usb_api_backend[api].designation);
+ break;
+ }
+ }
+ if (k >= 3) continue;
+ return api;
+ }
+ return 0;
+}
+
+static int set_composite_interface(struct libusb_context* ctx, struct libusb_device* dev,
+ char* dev_interface_path, char* device_id, uint8_t api)
+{
+ unsigned i;
+ struct windows_device_priv *priv = __device_priv(dev);
+ int interface_number;
+
+ if (priv->apib->id != USB_API_COMPOSITE) {
+ usbi_err(ctx, "program assertion failed: '%s' is not composite", device_id);
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ // Because MI_## are not necessarily in sequential order (some composite HID
+ // devices will have only MI_00 & MI_03 for instance), we retrieve the actual
+ // interface number from the path's MI value
+ interface_number = 0;
+ for (i=0; device_id[i] != 0; ) {
+ if ( (device_id[i++] == 'M') && (device_id[i++] == 'I')
+ && (device_id[i++] == '_') ) {
+ interface_number = (device_id[i++] - '0')*10;
+ interface_number += device_id[i] - '0';
+ break;
+ }
+ }
+
+ if (device_id[i] == 0) {
+ usbi_warn(ctx, "failure to read interface number for %s. Using default value %d",
+ device_id, interface_number);
+ }
+
+ // HID devices can have multiple collections (COL##) for each MI_## interface
+ if (priv->usb_interface[interface_number].path != NULL) {
+ if (api != USB_API_HID) {
+ usbi_warn(ctx, "program assertion failed %s is not an USB HID collection", device_id);
+ return LIBUSB_ERROR_OTHER;
+ }
+ usbi_dbg("interface[%d] already set - ignoring HID collection: %s",
+ interface_number, device_id);
+ return LIBUSB_ERROR_ACCESS;
+ }
+
+ usbi_dbg("interface[%d] = %s", interface_number, dev_interface_path);
+ priv->usb_interface[interface_number].path = dev_interface_path;
+ priv->usb_interface[interface_number].apib = &usb_api_backend[api];
+ if ((api == USB_API_HID) && (priv->hid == NULL)) {
+ priv->hid = calloc(1, sizeof(struct hid_device_priv));
+ }
+ priv->composite_api_flags |= 1<<api;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int set_hid_interface(struct libusb_context* ctx, struct libusb_device* dev,
+ char* dev_interface_path)
+{
+ struct windows_device_priv *priv = __device_priv(dev);
+
+ if (priv->hid == NULL) {
+ usbi_err(ctx, "program assertion failed: parent is not HID");
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+ priv->usb_interface[priv->hid->nb_interfaces].path = dev_interface_path;
+ priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID];
+ usbi_dbg("interface[%d] = %s", priv->hid->nb_interfaces, dev_interface_path);
+ priv->hid->nb_interfaces++;
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * get_device_list: libusb backend device enumeration function
+ */
+static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
+{
+ struct discovered_devs *discdevs = *_discdevs;
+ HDEVINFO dev_info;
+ SP_DEVINFO_DATA dev_info_data;
+ SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL;
+ GUID hid_guid;
+#define MAX_ENUM_GUIDS 64
+ const GUID* guid[MAX_ENUM_GUIDS];
+#define HCD_PASS 0
+#define HUB_PASS 1
+#define GEN_PASS 2
+#define DEV_PASS 3
+#define HID_PASS 4
+ int r = LIBUSB_SUCCESS;
+ unsigned int nb_guids, pass, i, j;
+ char path[MAX_PATH_LENGTH];
+ char strbuf[MAX_PATH_LENGTH];
+ struct libusb_device *dev, *parent_dev;
+ struct windows_device_priv *priv, *parent_priv;
+ char* dev_interface_path = NULL;
+ char* dev_id_path = NULL;
+ unsigned long session_id;
+ DWORD size, reg_type, port_nr, install_state;
+ HKEY key;
+ WCHAR guid_string_w[MAX_GUID_STRING_LENGTH];
+ GUID* if_guid;
+ LONG s;
+ uint8_t api;
+ // Keep a list of newly allocated devs to unref
+ libusb_device** unref_list;
+ unsigned int unref_size = 64;
+ unsigned int unref_cur = 0;
+
+ // PASS 1 : (re)enumerate HCDs (allows for HCD hotplug)
+ // PASS 2 : (re)enumerate HUBS
+ // PASS 3 : (re)enumerate generic USB devices (including driverless)
+ // and list additional USB device interface GUIDs to explore
+ // PASS 4 : (re)enumerate master USB devices that have a device interface
+ // PASS 5+: (re)enumerate device interfaced GUIDs (including HID) and
+ // set the device interfaces.
+
+ // Init the GUID table
+ guid[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER;
+ guid[HUB_PASS] = &GUID_DEVINTERFACE_USB_HUB;
+ guid[GEN_PASS] = NULL;
+ guid[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE;
+ HidD_GetHidGuid(&hid_guid);
+ guid[HID_PASS] = &hid_guid;
+ nb_guids = HID_PASS+1;
+
+ unref_list = malloc(unref_size*sizeof(libusb_device*));
+ if (unref_list == NULL) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ for (pass = 0; ((pass < nb_guids) && (r == LIBUSB_SUCCESS)); pass++) {
+//#define ENUM_DEBUG
+#ifdef ENUM_DEBUG
+ switch(pass) {
+ case HCD_PASS:
+ usbi_dbg("PROCESSING HCDs %s", guid_to_string(guid[pass]));
+ break;
+ case HUB_PASS:
+ usbi_dbg("PROCESSING HUBs %s", guid_to_string(guid[pass]));
+ break;
+ case DEV_PASS:
+ usbi_dbg("PROCESSING DEVs %s", guid_to_string(guid[pass]));
+ break;
+ case GEN_PASS:
+ usbi_dbg("PROCESSING GENs");
+ break;
+ case HID_PASS:
+ usbi_dbg("PROCESSING HIDs %s", guid_to_string(guid[pass]));
+ break;
+ default:
+ usbi_dbg("PROCESSING EXTs %s", guid_to_string(guid[pass]));
+ break;
+ }
+#endif
+ for (i = 0; ; i++) {
+ // safe loop: free up any (unprotected) dynamic resource
+ // NB: this is always executed before breaking the loop
+ safe_free(dev_interface_details);
+ safe_free(dev_interface_path);
+ safe_free(dev_id_path);
+ session_id = 0;
+ priv = parent_priv = NULL;
+ dev = parent_dev = NULL;
+
+ // Safe loop: end of loop conditions
+ if (r != LIBUSB_SUCCESS) {
+ break;
+ }
+ if ((pass == HCD_PASS) && (i == UINT8_MAX)) {
+ usbi_warn(ctx, "program assertion failed - found more than %d buses, skipping the rest.", UINT8_MAX);
+ break;
+ }
+ if (pass != GEN_PASS) {
+ // Except for GEN, all passes deal with device interfaces
+ dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, guid[pass], i);
+ if (dev_interface_details == NULL) {
+ break;
+ } else {
+ dev_interface_path = sanitize_path(dev_interface_details->DevicePath);
+ if (dev_interface_path == NULL) {
+ usbi_warn(ctx, "could not sanitize device interface path for '%s'", dev_interface_details->DevicePath);
+ continue;
+ }
+ }
+ } else {
+ if (!get_devinfo_data(ctx, &dev_info, &dev_info_data, i)) {
+ break;
+ }
+ }
+
+ // Read the Device ID path. This is what we'll use as UID
+ // Note that if the device is plugged in a different port or hub, the Device ID changes
+ if (CM_Get_Device_IDA(dev_info_data.DevInst, path, sizeof(path), 0) != CR_SUCCESS) {
+ usbi_warn(ctx, "could not read the device id path for devinst %X, skipping",
+ dev_info_data.DevInst);
+ continue;
+ }
+ dev_id_path = sanitize_path(path);
+ if (dev_id_path == NULL) {
+ usbi_warn(ctx, "could not sanitize device id path for devinst %X, skipping",
+ dev_info_data.DevInst);
+ continue;
+ }
+#ifdef ENUM_DEBUG
+ usbi_dbg("PRO: %s", dev_id_path);
+#endif
+
+ // The SPDRP_ADDRESS for USB devices is the device port number on the hub
+ port_nr = 0;
+ if ((pass >= HUB_PASS) && (pass <= GEN_PASS)) {
+ if ( (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ADDRESS,
+ &reg_type, (BYTE*)&port_nr, 4, &size))
+ || (size != 4) ) {
+ usbi_warn(ctx, "could not retrieve port number for device '%s', skipping: %s",
+ dev_id_path, windows_error_str(0));
+ continue;
+ }
+ }
+
+ // Set API to use or get additional data from generic pass
+ api = USB_API_UNSUPPORTED;
+ switch (pass) {
+ case HCD_PASS:
+ break;
+ case GEN_PASS:
+ // We use the GEN pass to detect driverless devices...
+ size = sizeof(strbuf);
+ if (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_DRIVER,
+ &reg_type, (BYTE*)strbuf, size, &size)) {
+ usbi_info(ctx, "The following device has no driver: '%s'", dev_id_path);
+ usbi_info(ctx, "libusb will not be able to access it.");
+ }
+ // ...and to add the additional device interface GUIDs
+ key = pSetupDiOpenDevRegKey(dev_info, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
+ if (key != INVALID_HANDLE_VALUE) {
+ size = sizeof(guid_string_w);
+ s = pRegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, &reg_type,
+ (BYTE*)guid_string_w, &size);
+ pRegCloseKey(key);
+ if (s == ERROR_SUCCESS) {
+ if (nb_guids >= MAX_ENUM_GUIDS) {
+ // If this assert is ever reported, grow a GUID table dynamically
+ usbi_err(ctx, "program assertion failed: too many GUIDs");
+ LOOP_BREAK(LIBUSB_ERROR_OVERFLOW);
+ }
+ if_guid = calloc(1, sizeof(GUID));
+ pCLSIDFromString(guid_string_w, if_guid);
+ guid[nb_guids++] = if_guid;
+ usbi_dbg("extra GUID: %s", guid_to_string(if_guid));
+ }
+ }
+ break;
+ case HID_PASS:
+ api = USB_API_HID;
+ break;
+ default:
+ // Get the API type (after checking that the driver installation is OK)
+ if ( (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_INSTALL_STATE,
+ &reg_type, (BYTE*)&install_state, 4, &size))
+ || (size != 4) ){
+ usbi_warn(ctx, "could not detect installation state of driver for '%s': %s",
+ dev_id_path, windows_error_str(0));
+ } else if (install_state != 0) {
+ usbi_warn(ctx, "driver for device '%s' is reporting an issue (code: %d) - skipping",
+ dev_id_path, install_state);
+ continue;
+ }
+ api = get_api_type(ctx, &dev_info, &dev_info_data);
+ break;
+ }
+
+ // Find parent device (for the passes that need it)
+ switch (pass) {
+ case HCD_PASS:
+ case DEV_PASS:
+ case HUB_PASS:
+ break;
+ default:
+ session_id = get_ancestor_session_id(dev_info_data.DevInst, 1);
+ if (session_id == 0) {
+ usbi_err(ctx, "program assertion failed: orphan device '%s'", dev_id_path);
+ LOOP_BREAK(LIBUSB_ERROR_NO_DEVICE);
+ }
+ parent_dev = usbi_get_device_by_session_id(ctx, session_id);
+ // Composite HID devices have double indirection => Check grandparent
+ if (pass == HID_PASS) {
+ session_id = get_ancestor_session_id(dev_info_data.DevInst, 2);
+ if (session_id == 0) {
+ usbi_err(ctx, "program assertion failed: no grandparent for '%s'", dev_id_path);
+ LOOP_BREAK(LIBUSB_ERROR_NO_DEVICE);
+ } else if (session_id == ~0) {
+ usbi_dbg("skipping non USB HID interface '%s'", dev_id_path);
+ continue;
+ }
+ dev = usbi_get_device_by_session_id(ctx, session_id);
+ if (dev == NULL) {
+ usbi_err(ctx, "program assertion failed: unlisted grandparent for '%s'", dev_id_path);
+ LOOP_BREAK(LIBUSB_ERROR_NO_DEVICE);
+ }
+ if (__device_priv(dev)->apib->id == USB_API_COMPOSITE) {
+ parent_dev = dev;
+ }
+ }
+ if (parent_dev == NULL) {
+ // This can occur if the OS only reports a newly plugged device after we started enum,
+ // eg. HID parent not listed on GEN pass, but children listed on HID pass
+ usbi_warn(ctx, "unlisted parent for '%s' (newly connected device?) - ignoring", dev_id_path);
+ continue;
+ }
+ parent_priv = __device_priv(parent_dev);
+ // virtual USB devices are also listed during GEN - don't process these yet
+ if ( (pass == GEN_PASS) && (parent_priv->apib->id != USB_API_HUB) ) {
+ continue;
+ }
+ break;
+ }
+
+ // Create new or match existing device, using the (hashed) device_id as session id
+ if (pass <= DEV_PASS) { // For subsequent passes, we'll lookup the parent
+ // These are the passes that create "new" devices
+ session_id = htab_hash(dev_id_path);
+ dev = usbi_get_device_by_session_id(ctx, session_id);
+ if (dev == NULL) {
+ if (pass == DEV_PASS) {
+ // This can occur if the OS only reports a newly plugged device after we started enum
+ usbi_warn(ctx, "'%s' was only detected in late pass (newly connected device?)"
+ " - ignoring", dev_id_path);
+ continue;
+ }
+ usbi_dbg("allocating new device for session [%X]", session_id);
+ if ((dev = usbi_alloc_device(ctx, session_id)) == NULL) {
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+ }
+ windows_device_priv_init(dev);
+ // Keep track of devices that need unref
+ unref_list[unref_cur++] = dev;
+ if (unref_cur > unref_size) {
+ unref_size += 64;
+ unref_list = realloc(unref_list, unref_size*sizeof(libusb_device*));
+ if (unref_list == NULL) {
+ usbi_err(ctx, "could not realloc list for unref - aborting.");
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+ }
+ }
+ } else {
+ usbi_dbg("found existing device for session [%X]", session_id);
+ }
+ priv = __device_priv(dev);
+ }
+
+ // Setup device
+ switch (pass) {
+ case HCD_PASS:
+ dev->bus_number = (uint8_t)(i + 1); // bus 0 is reserved for disconnected
+ dev->device_address = 0;
+ dev->num_configurations = 0;
+ priv->apib = &usb_api_backend[USB_API_HUB];
+ priv->depth = UINT8_MAX; // Overflow to 0 for HCD Hubs
+ priv->path = dev_interface_path; dev_interface_path = NULL;
+ break;
+ case DEV_PASS:
+ // Take care of API initialization
+ priv->path = dev_interface_path; dev_interface_path = NULL;
+ priv->apib = &usb_api_backend[api];
+ switch(api) {
+ case USB_API_COMPOSITE:
+ break;
+ case USB_API_HID:
+ safe_free(priv->hid);
+ priv->hid = calloc(1, sizeof(struct hid_device_priv));
+ if (priv->hid == NULL) {
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+ }
+ priv->hid->nb_interfaces = 0;
+ break;
+ default:
+ // For other devices, the first interface is the same as the device
+ priv->usb_interface[0].path = malloc(safe_strlen(priv->path)+1);
+ if (priv->usb_interface[0].path != NULL) {
+ safe_strcpy(priv->usb_interface[0].path, safe_strlen(priv->path)+1, priv->path);
+ }
+ // The following is needed if we want API calls to work for both simple
+ // and composite devices.
+ for(j=0; j<USB_MAXINTERFACES; j++) {
+ priv->usb_interface[j].apib = &usb_api_backend[api];
+ }
+ break;
+ }
+ break;
+ case HUB_PASS:
+ priv->apib = &usb_api_backend[api];
+ priv->path = dev_interface_path; dev_interface_path = NULL;
+ break;
+ case GEN_PASS:
+ r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_id_path, dev_info_data.DevInst);
+ if (r == LIBUSB_SUCCESS) {
+ // Append device to the list of discovered devices
+ discdevs = discovered_devs_append(*_discdevs, dev);
+ if (!discdevs) {
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
+ }
+ *_discdevs = discdevs;
+ } else if (r == LIBUSB_ERROR_NO_DEVICE) {
+ // This can occur if the device was disconnected but Windows hasn't
+ // refreshed its enumeration yet - in that case, we ignore the device
+ r = LIBUSB_SUCCESS;
+ }
+ break;
+ default: // HID_PASS and later
+ if (parent_priv->apib->id == USB_API_HID) {
+ usbi_dbg("setting HID interface for [%lX]:", parent_dev->session_data);
+ r = set_hid_interface(ctx, parent_dev, dev_interface_path);
+ if (r != LIBUSB_SUCCESS) LOOP_BREAK(r);
+ dev_interface_path = NULL;
+ } else if (parent_priv->apib->id == USB_API_COMPOSITE) {
+ usbi_dbg("setting composite interface for [%lX]:", parent_dev->session_data);
+ switch (set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id_path, api)) {
+ case LIBUSB_SUCCESS:
+ dev_interface_path = NULL;
+ break;
+ case LIBUSB_ERROR_ACCESS:
+ // interface has already been set => make sure dev_interface_path is freed then
+ break;
+ default:
+ LOOP_BREAK(r);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ // Free any additional GUIDs
+ for (pass = HID_PASS+1; pass < nb_guids; pass++) {
+ safe_free(guid[pass]);
+ }
+
+ // Unref newly allocated devs
+ for (i=0; i<unref_cur; i++) {
+ safe_unref_device(unref_list[i]);
+ }
+ safe_free(unref_list);
+
+ return r;
+}
+
+/*
+ * exit: libusb backend deinitialization function
+ */
+static void windows_exit(void)
+{
+ int i;
+ HANDLE semaphore;
+ char sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
+
+ sprintf(sem_name, "libusb_init%08X", (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
+ semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name);
+ if (semaphore == NULL) {
+ return;
+ }
+
+ // A successful wait brings our semaphore count to 0 (unsignaled)
+ // => any concurent wait stalls until the semaphore release
+ if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) {
+ CloseHandle(semaphore);
+ return;
+ }
+
+ // Only works if exits and inits are balanced exactly
+ if (--concurrent_usage < 0) { // Last exit
+ for (i=0; i<USB_API_MAX; i++) {
+ usb_api_backend[i].exit();
+ }
+ exit_polling();
+
+ if (timer_thread) {
+ SetEvent(timer_request[1]); // actually the signal to quit the thread.
+ if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) {
+ usbi_dbg("could not wait for timer thread to quit");
+ TerminateThread(timer_thread, 1);
+ }
+ CloseHandle(timer_thread);
+ timer_thread = NULL;
+ }
+ for (i = 0; i < 2; i++) {
+ if (timer_request[i]) {
+ CloseHandle(timer_request[i]);
+ timer_request[i] = NULL;
+ }
+ }
+ if (timer_response) {
+ CloseHandle(timer_response);
+ timer_response = NULL;
+ }
+ if (timer_mutex) {
+ CloseHandle(timer_mutex);
+ timer_mutex = NULL;
+ }
+ htab_destroy();
+ }
+
+ ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
+ CloseHandle(semaphore);
+}
+
+static int windows_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian)
+{
+ struct windows_device_priv *priv = __device_priv(dev);
+
+ memcpy(buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH);
+ *host_endian = 0;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int windows_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
+{
+ struct windows_device_priv *priv = __device_priv(dev);
+ PUSB_CONFIGURATION_DESCRIPTOR config_header;
+ size_t size;
+
+ // config index is zero based
+ if (config_index >= dev->num_configurations)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ if ((priv->config_descriptor == NULL) || (priv->config_descriptor[config_index] == NULL))
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptor[config_index];
+
+ size = min(config_header->wTotalLength, len);
+ memcpy(buffer, priv->config_descriptor[config_index], size);
+
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * return the cached copy of the active config descriptor
+ */
+static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian)
+{
+ struct windows_device_priv *priv = __device_priv(dev);
+
+ if (priv->active_config == 0)
+ return LIBUSB_ERROR_NOT_FOUND;
+
+ // config index is zero based
+ return windows_get_config_descriptor(dev, (uint8_t)(priv->active_config-1), buffer, len, host_endian);
+}
+
+static int windows_open(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+
+ if (priv->apib == NULL) {
+ usbi_err(ctx, "program assertion failed - device is not initialized");
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ return priv->apib->open(dev_handle);
+}
+
+static void windows_close(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+
+ priv->apib->close(dev_handle);
+}
+
+static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+
+ if (priv->active_config == 0) {
+ *config = 0;
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ *config = priv->active_config;
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * from http://msdn.microsoft.com/en-us/library/ms793522.aspx: "The port driver
+ * does not currently expose a service that allows higher-level drivers to set
+ * the configuration."
+ */
+static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ int r = LIBUSB_SUCCESS;
+
+ if (config >= USB_MAXCONFIG)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_OUT |
+ LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
+ LIBUSB_REQUEST_SET_CONFIGURATION, (uint16_t)config,
+ 0, NULL, 0, 1000);
+
+ if (r == LIBUSB_SUCCESS) {
+ priv->active_config = (uint8_t)config;
+ }
+ return r;
+}
+
+static int windows_claim_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ int r = LIBUSB_SUCCESS;
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+
+ if (iface >= USB_MAXINTERFACES)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ safe_free(priv->usb_interface[iface].endpoint);
+ priv->usb_interface[iface].nb_endpoints= 0;
+
+ r = priv->apib->claim_interface(dev_handle, iface);
+
+ if (r == LIBUSB_SUCCESS) {
+ r = windows_assign_endpoints(dev_handle, iface, 0);
+ }
+
+ return r;
+}
+
+static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
+{
+ int r = LIBUSB_SUCCESS;
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+
+ safe_free(priv->usb_interface[iface].endpoint);
+ priv->usb_interface[iface].nb_endpoints= 0;
+
+ r = priv->apib->set_interface_altsetting(dev_handle, iface, altsetting);
+
+ if (r == LIBUSB_SUCCESS) {
+ r = windows_assign_endpoints(dev_handle, iface, altsetting);
+ }
+
+ return r;
+}
+
+static int windows_release_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+
+ windows_set_interface_altsetting(dev_handle, iface, 0);
+ return priv->apib->release_interface(dev_handle, iface);
+}
+
+static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ return priv->apib->clear_halt(dev_handle, endpoint);
+}
+
+static int windows_reset_device(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ return priv->apib->reset_device(dev_handle);
+}
+
+// The 3 functions below are unlikely to ever get supported on Windows
+static int windows_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface)
+{
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+static int windows_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
+{
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+static int windows_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
+{
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+static void windows_destroy_device(struct libusb_device *dev)
+{
+ windows_device_priv_release(dev);
+}
+
+static void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
+{
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+
+ usbi_free_fd(transfer_priv->pollable_fd.fd);
+ safe_free(transfer_priv->hid_buffer);
+#if defined(AUTO_CLAIM)
+ // When auto claim is in use, attempt to release the auto-claimed interface
+ auto_release(itransfer);
+#endif
+}
+
+static int submit_bulk_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ int r;
+
+ r = priv->apib->submit_bulk_transfer(itransfer);
+ if (r != LIBUSB_SUCCESS) {
+ return r;
+ }
+
+ usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
+ (short)((transfer->endpoint & LIBUSB_ENDPOINT_IN)?POLLIN:POLLOUT));
+#if !defined(DYNAMIC_FDS)
+ usbi_fd_notification(ctx);
+#endif
+
+ return LIBUSB_SUCCESS;
+}
+
+static int submit_iso_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ int r;
+
+ r = priv->apib->submit_iso_transfer(itransfer);
+ if (r != LIBUSB_SUCCESS) {
+ return r;
+ }
+
+ usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
+ (short)((transfer->endpoint & LIBUSB_ENDPOINT_IN)?POLLIN:POLLOUT));
+#if !defined(DYNAMIC_FDS)
+ usbi_fd_notification(ctx);
+#endif
+
+ return LIBUSB_SUCCESS;
+}
+
+static int submit_control_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ int r;
+
+ r = priv->apib->submit_control_transfer(itransfer);
+ if (r != LIBUSB_SUCCESS) {
+ return r;
+ }
+
+ usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
+#if !defined(DYNAMIC_FDS)
+ usbi_fd_notification(ctx);
+#endif
+
+ return LIBUSB_SUCCESS;
+
+}
+
+static int windows_submit_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ return submit_control_transfer(itransfer);
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ return submit_bulk_transfer(itransfer);
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ return submit_iso_transfer(itransfer);
+ default:
+ usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+}
+
+static int windows_abort_control(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+
+ return priv->apib->abort_control(itransfer);
+}
+
+static int windows_abort_transfers(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+
+ return priv->apib->abort_transfers(itransfer);
+}
+
+static int windows_cancel_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+#if defined(FORCE_INSTANT_TIMEOUTS)
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+
+ // Forces instant overlapped completion on timeouts - use at your own risks
+ if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) {
+ transfer_priv->pollable_fd.overlapped->Internal &= ~STATUS_PENDING;
+ }
+#endif
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ return windows_abort_control(itransfer);
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ return windows_abort_transfers(itransfer);
+ default:
+ usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+}
+
+static void windows_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ int status;
+
+ usbi_dbg("handling I/O completion with errcode %d", io_result);
+
+ switch(io_result) {
+ case NO_ERROR:
+ status = priv->apib->copy_transfer_data(itransfer, io_size);
+ break;
+ case ERROR_GEN_FAILURE:
+ usbi_dbg("detected endpoint stall");
+ status = LIBUSB_TRANSFER_STALL;
+ break;
+ case ERROR_SEM_TIMEOUT:
+ usbi_dbg("detected semaphore timeout");
+ status = LIBUSB_TRANSFER_TIMED_OUT;
+ break;
+ case ERROR_OPERATION_ABORTED:
+ if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) {
+ usbi_dbg("detected timeout");
+ status = LIBUSB_TRANSFER_TIMED_OUT;
+ } else {
+ usbi_dbg("detected operation aborted");
+ status = LIBUSB_TRANSFER_CANCELLED;
+ }
+ break;
+ default:
+ usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error: %s", windows_error_str(0));
+ status = LIBUSB_TRANSFER_ERROR;
+ break;
+ }
+ windows_clear_transfer_priv(itransfer); // Cancel polling
+ usbi_handle_transfer_completion(itransfer, status);
+}
+
+static void windows_handle_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ windows_transfer_callback (itransfer, io_result, io_size);
+ break;
+ default:
+ usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
+ }
+}
+
+static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds_t nfds, int num_ready)
+{
+ struct windows_transfer_priv* transfer_priv = NULL;
+ nfds_t i = 0;
+ bool found = false;
+ struct usbi_transfer *transfer;
+ DWORD io_size, io_result;
+
+ usbi_mutex_lock(&ctx->open_devs_lock);
+ for (i = 0; i < nfds && num_ready > 0; i++) {
+
+ usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents);
+
+ if (!fds[i].revents) {
+ continue;
+ }
+
+ num_ready--;
+
+ // Because a Windows OVERLAPPED is used for poll emulation,
+ // a pollable fd is created and stored with each transfer
+ usbi_mutex_lock(&ctx->flying_transfers_lock);
+ list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+ transfer_priv = usbi_transfer_get_os_priv(transfer);
+ if (transfer_priv->pollable_fd.fd == fds[i].fd) {
+ found = true;
+ break;
+ }
+ }
+ usbi_mutex_unlock(&ctx->flying_transfers_lock);
+
+ if (found) {
+ // Handle async requests that completed synchronously first
+ if (HasOverlappedIoCompletedSync(transfer_priv->pollable_fd.overlapped)) {
+ io_result = NO_ERROR;
+ io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh;
+ // Regular async overlapped
+ } else if (GetOverlappedResult(transfer_priv->pollable_fd.handle,
+ transfer_priv->pollable_fd.overlapped, &io_size, false)) {
+ io_result = NO_ERROR;
+ } else {
+ io_result = GetLastError();
+ }
+ usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd);
+ // let handle_callback free the event using the transfer wfd
+ // If you don't use the transfer wfd, you run a risk of trying to free a
+ // newly allocated wfd that took the place of the one from the transfer.
+ windows_handle_callback(transfer, io_result, io_size);
+ } else {
+ usbi_err(ctx, "could not find a matching transfer for fd %x", fds[i]);
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+ }
+
+ usbi_mutex_unlock(&ctx->open_devs_lock);
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * Monotonic and real time functions
+ */
+unsigned __stdcall windows_clock_gettime_threaded(void* param)
+{
+ LARGE_INTEGER hires_counter, li_frequency;
+ LONG nb_responses;
+ int timer_index;
+
+ // Init - find out if we have access to a monotonic (hires) timer
+ if (!QueryPerformanceFrequency(&li_frequency)) {
+ usbi_dbg("no hires timer available on this platform");
+ hires_frequency = 0;
+ hires_ticks_to_ps = UINT64_C(0);
+ } else {
+ hires_frequency = li_frequency.QuadPart;
+ // The hires frequency can go as high as 4 GHz, so we'll use a conversion
+ // to picoseconds to compute the tv_nsecs part in clock_gettime
+ hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
+ usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
+ }
+
+ // Main loop - wait for requests
+ while (1) {
+ timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0;
+ if ( (timer_index != 0) && (timer_index != 1) ) {
+ usbi_dbg("failure to wait on requests: %s", windows_error_str(0));
+ continue;
+ }
+ if (request_count[timer_index] == 0) {
+ // Request already handled
+ ResetEvent(timer_request[timer_index]);
+ // There's still a possiblity that a thread sends a request between the
+ // time we test request_count[] == 0 and we reset the event, in which case
+ // the request would be ignored. The simple solution to that is to test
+ // request_count again and process requests if non zero.
+ if (request_count[timer_index] == 0)
+ continue;
+ }
+ switch (timer_index) {
+ case 0:
+ WaitForSingleObject(timer_mutex, INFINITE);
+ // Requests to this thread are for hires always
+ if (QueryPerformanceCounter(&hires_counter) != 0) {
+ timer_tp.tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
+ timer_tp.tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency)/1000) * hires_ticks_to_ps);
+ } else {
+ // Fallback to real-time if we can't get monotonic value
+ // Note that real-time clock does not wait on the mutex or this thread.
+ windows_clock_gettime(USBI_CLOCK_REALTIME, &timer_tp);
+ }
+ ReleaseMutex(timer_mutex);
+
+ INIT_INTERLOCKEDEXCHANGE;
+ nb_responses = pInterlockedExchange((LONG*)&request_count[0], 0);
+ if ( (nb_responses)
+ && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0) ) {
+ usbi_dbg("unable to release timer semaphore %d: %s", windows_error_str(0));
+ }
+ continue;
+ case 1: // time to quit
+ usbi_dbg("timer thread quitting");
+ return 0;
+ }
+ }
+ usbi_dbg("ERROR: broken timer thread");
+ return 1;
+}
+
+static int windows_clock_gettime(int clk_id, struct timespec *tp)
+{
+ FILETIME filetime;
+ ULARGE_INTEGER rtime;
+ DWORD r;
+ switch(clk_id) {
+ case USBI_CLOCK_MONOTONIC:
+ if (hires_frequency != 0) {
+ INIT_INTERLOCKEDINCREMENT;
+ while (1) {
+ pInterlockedIncrement((LONG*)&request_count[0]);
+ SetEvent(timer_request[0]);
+ r = WaitForSingleObject(timer_response, TIMER_REQUEST_RETRY_MS);
+ switch(r) {
+ case WAIT_OBJECT_0:
+ WaitForSingleObject(timer_mutex, INFINITE);
+ *tp = timer_tp;
+ ReleaseMutex(timer_mutex);
+ return LIBUSB_SUCCESS;
+ case WAIT_TIMEOUT:
+ usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
+ break; // Retry until successful
+ default:
+ usbi_dbg("WaitForSingleObject failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_OTHER;
+ }
+ }
+ }
+ // Fall through and return real-time if monotonic was not detected @ timer init
+ case USBI_CLOCK_REALTIME:
+ // We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx
+ // with a predef epoch_time to have an epoch that starts at 1970.01.01 00:00
+ // Note however that our resolution is bounded by the Windows system time
+ // functions and is at best of the order of 1 ms (or, usually, worse)
+ GetSystemTimeAsFileTime(&filetime);
+ rtime.LowPart = filetime.dwLowDateTime;
+ rtime.HighPart = filetime.dwHighDateTime;
+ rtime.QuadPart -= epoch_time;
+ tp->tv_sec = (long)(rtime.QuadPart / 10000000);
+ tp->tv_nsec = (long)((rtime.QuadPart % 10000000)*100);
+ return LIBUSB_SUCCESS;
+ default:
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+}
+
+
+// NB: MSVC6 does not support named initializers.
+const struct usbi_os_backend windows_backend = {
+ "Windows",
+ windows_init,
+ windows_exit,
+
+ windows_get_device_list,
+ windows_open,
+ windows_close,
+
+ windows_get_device_descriptor,
+ windows_get_active_config_descriptor,
+ windows_get_config_descriptor,
+
+ windows_get_configuration,
+ windows_set_configuration,
+ windows_claim_interface,
+ windows_release_interface,
+
+ windows_set_interface_altsetting,
+ windows_clear_halt,
+ windows_reset_device,
+
+ windows_kernel_driver_active,
+ windows_detach_kernel_driver,
+ windows_attach_kernel_driver,
+
+ windows_destroy_device,
+
+ windows_submit_transfer,
+ windows_cancel_transfer,
+ windows_clear_transfer_priv,
+
+ windows_handle_events,
+
+ windows_clock_gettime,
+#if defined(USBI_TIMERFD_AVAILABLE)
+ NULL,
+#endif
+ sizeof(struct windows_device_priv),
+ sizeof(struct windows_device_handle_priv),
+ sizeof(struct windows_transfer_priv),
+ 0,
+};
+
+
+/*
+ * USB API backends
+ */
+static int unsupported_init(struct libusb_context *ctx) {
+ return LIBUSB_SUCCESS;
+}
+static int unsupported_exit(void) {
+ return LIBUSB_SUCCESS;
+}
+static int unsupported_open(struct libusb_device_handle *dev_handle) {
+ PRINT_UNSUPPORTED_API(open);
+}
+static void unsupported_close(struct libusb_device_handle *dev_handle) {
+ usbi_dbg("unsupported API call for 'close'");
+}
+static int unsupported_claim_interface(struct libusb_device_handle *dev_handle, int iface) {
+ PRINT_UNSUPPORTED_API(claim_interface);
+}
+static int unsupported_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) {
+ PRINT_UNSUPPORTED_API(set_interface_altsetting);
+}
+static int unsupported_release_interface(struct libusb_device_handle *dev_handle, int iface) {
+ PRINT_UNSUPPORTED_API(release_interface);
+}
+static int unsupported_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) {
+ PRINT_UNSUPPORTED_API(clear_halt);
+}
+static int unsupported_reset_device(struct libusb_device_handle *dev_handle) {
+ PRINT_UNSUPPORTED_API(reset_device);
+}
+static int unsupported_submit_bulk_transfer(struct usbi_transfer *itransfer) {
+ PRINT_UNSUPPORTED_API(submit_bulk_transfer);
+}
+static int unsupported_submit_iso_transfer(struct usbi_transfer *itransfer) {
+ PRINT_UNSUPPORTED_API(submit_iso_transfer);
+}
+static int unsupported_submit_control_transfer(struct usbi_transfer *itransfer) {
+ PRINT_UNSUPPORTED_API(submit_control_transfer);
+}
+static int unsupported_abort_control(struct usbi_transfer *itransfer) {
+ PRINT_UNSUPPORTED_API(abort_control);
+}
+static int unsupported_abort_transfers(struct usbi_transfer *itransfer) {
+ PRINT_UNSUPPORTED_API(abort_transfers);
+}
+static int unsupported_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) {
+ PRINT_UNSUPPORTED_API(copy_transfer_data);
+}
+
+// These names must be uppercase
+const char* hub_driver_names[] = {"USBHUB"};
+const char* composite_driver_names[] = {"USBCCGP"};
+const char* winusb_driver_names[] = {"WINUSB"};
+const char* hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"};
+const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
+ {
+ USB_API_UNSUPPORTED,
+ "Unsupported API",
+ &CLASS_GUID_UNSUPPORTED,
+ NULL,
+ 0,
+ unsupported_init,
+ unsupported_exit,
+ unsupported_open,
+ unsupported_close,
+ unsupported_claim_interface,
+ unsupported_set_interface_altsetting,
+ unsupported_release_interface,
+ unsupported_clear_halt,
+ unsupported_reset_device,
+ unsupported_submit_bulk_transfer,
+ unsupported_submit_iso_transfer,
+ unsupported_submit_control_transfer,
+ unsupported_abort_control,
+ unsupported_abort_transfers,
+ unsupported_copy_transfer_data,
+ }, {
+ USB_API_HUB,
+ "HUB API",
+ &CLASS_GUID_UNSUPPORTED,
+ hub_driver_names,
+ sizeof(hub_driver_names)/sizeof(hub_driver_names[0]),
+ unsupported_init,
+ unsupported_exit,
+ hub_open,
+ hub_close,
+ unsupported_claim_interface,
+ unsupported_set_interface_altsetting,
+ unsupported_release_interface,
+ unsupported_clear_halt,
+ unsupported_reset_device,
+ unsupported_submit_bulk_transfer,
+ unsupported_submit_iso_transfer,
+ unsupported_submit_control_transfer,
+ unsupported_abort_control,
+ unsupported_abort_transfers,
+ unsupported_copy_transfer_data,
+ }, {
+ USB_API_COMPOSITE,
+ "Composite API",
+ &CLASS_GUID_COMPOSITE,
+ composite_driver_names,
+ sizeof(composite_driver_names)/sizeof(composite_driver_names[0]),
+ composite_init,
+ composite_exit,
+ composite_open,
+ composite_close,
+ composite_claim_interface,
+ composite_set_interface_altsetting,
+ composite_release_interface,
+ composite_clear_halt,
+ composite_reset_device,
+ composite_submit_bulk_transfer,
+ composite_submit_iso_transfer,
+ composite_submit_control_transfer,
+ composite_abort_control,
+ composite_abort_transfers,
+ composite_copy_transfer_data,
+ }, {
+ USB_API_WINUSB,
+ "WinUSB API",
+ &CLASS_GUID_LIBUSB_WINUSB,
+ winusb_driver_names,
+ sizeof(winusb_driver_names)/sizeof(winusb_driver_names[0]),
+ winusb_init,
+ winusb_exit,
+ winusb_open,
+ winusb_close,
+ winusb_claim_interface,
+ winusb_set_interface_altsetting,
+ winusb_release_interface,
+ winusb_clear_halt,
+ winusb_reset_device,
+ winusb_submit_bulk_transfer,
+ unsupported_submit_iso_transfer,
+ winusb_submit_control_transfer,
+ winusb_abort_control,
+ winusb_abort_transfers,
+ winusb_copy_transfer_data,
+ }, {
+ USB_API_HID,
+ "HID API",
+ &CLASS_GUID_HID,
+ hid_driver_names,
+ sizeof(hid_driver_names)/sizeof(hid_driver_names[0]),
+ hid_init,
+ hid_exit,
+ hid_open,
+ hid_close,
+ hid_claim_interface,
+ hid_set_interface_altsetting,
+ hid_release_interface,
+ hid_clear_halt,
+ hid_reset_device,
+ hid_submit_bulk_transfer,
+ unsupported_submit_iso_transfer,
+ hid_submit_control_transfer,
+ hid_abort_transfers,
+ hid_abort_transfers,
+ hid_copy_transfer_data,
+ },
+};
+
+
+/*
+ * HUB API functions - only cached descriptors readout for now
+ * might be expanded if
+ */
+static int hub_open(struct libusb_device_handle *dev_handle)
+{
+ return LIBUSB_SUCCESS;
+}
+
+static void hub_close(struct libusb_device_handle *dev_handle)
+{
+}
+
+/*
+ * WinUSB API functions
+ */
+static int winusb_init(struct libusb_context *ctx)
+{
+ DLL_LOAD(winusb.dll, WinUsb_Initialize, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_Free, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_GetAssociatedInterface, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_GetDescriptor, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_QueryInterfaceSettings, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_QueryDeviceInformation, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_SetCurrentAlternateSetting, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_GetCurrentAlternateSetting, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_QueryPipe, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_SetPipePolicy, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_GetPipePolicy, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_ReadPipe, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_WritePipe, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_ControlTransfer, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_ResetPipe, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_AbortPipe, TRUE);
+ DLL_LOAD(winusb.dll, WinUsb_FlushPipe, TRUE);
+
+ api_winusb_available = true;
+ return LIBUSB_SUCCESS;
+}
+
+static int winusb_exit(void)
+{
+ return LIBUSB_SUCCESS;
+}
+
+// NB: open and close must ensure that they only handle interface of
+// the right API type, as these functions can be called wholesale from
+// composite_open(), with interfaces belonging to different APIs
+static int winusb_open(struct libusb_device_handle *dev_handle)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+
+ HANDLE file_handle;
+ int i;
+
+ CHECK_WINUSB_AVAILABLE;
+
+ // WinUSB requires a seperate handle for each interface
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if ( (priv->usb_interface[i].path != NULL)
+ && (priv->usb_interface[i].apib->id == USB_API_WINUSB) ) {
+ file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+ if (file_handle == INVALID_HANDLE_VALUE) {
+ usbi_err(ctx, "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0));
+ switch(GetLastError()) {
+ case ERROR_FILE_NOT_FOUND: // The device was disconnected
+ return LIBUSB_ERROR_NO_DEVICE;
+ case ERROR_ACCESS_DENIED:
+ return LIBUSB_ERROR_ACCESS;
+ default:
+ return LIBUSB_ERROR_IO;
+ }
+ }
+ handle_priv->interface_handle[i].dev_handle = file_handle;
+ }
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static void winusb_close(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ HANDLE file_handle;
+ int i;
+
+ if (!api_winusb_available)
+ return;
+
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if (priv->usb_interface[i].apib->id == USB_API_WINUSB) {
+ file_handle = handle_priv->interface_handle[i].dev_handle;
+ if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) {
+ CloseHandle(file_handle);
+ }
+ }
+ }
+}
+
+static int winusb_configure_endpoints(struct libusb_device_handle *dev_handle, int iface)
+{
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ HANDLE winusb_handle = handle_priv->interface_handle[iface].api_handle;
+ UCHAR policy;
+ ULONG timeout = 0;
+ uint8_t endpoint_address;
+ int i;
+
+ CHECK_WINUSB_AVAILABLE;
+
+ // With handle and enpoints set (in parent), we can setup the default pipe properties
+ // see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx
+ for (i=-1; i<priv->usb_interface[iface].nb_endpoints; i++) {
+ endpoint_address =(i==-1)?0:priv->usb_interface[iface].endpoint[i];
+ if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address,
+ PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout)) {
+ usbi_dbg("failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address);
+ }
+ if (i == -1) continue; // Other policies don't apply to control endpoint
+ policy = false;
+ if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address,
+ SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy)) {
+ usbi_dbg("failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address);
+ }
+ if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address,
+ IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy)) {
+ usbi_dbg("failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address);
+ }
+ if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address,
+ ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy)) {
+ usbi_dbg("failed to disable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address);
+ }
+ policy = true;
+ if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address,
+ AUTO_CLEAR_STALL, sizeof(UCHAR), &policy)) {
+ usbi_dbg("failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address);
+ }
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE);
+ HANDLE file_handle, winusb_handle;
+
+ CHECK_WINUSB_AVAILABLE;
+
+ // If the device is composite, but using the default Windows composite parent driver (usbccgp)
+ // or if it's the first WinUSB interface, we get a handle through WinUsb_Initialize().
+ if ((is_using_usbccgp) || (iface == 0)) {
+ // composite device (independent interfaces) or interface 0
+ winusb_handle = handle_priv->interface_handle[iface].api_handle;
+ file_handle = handle_priv->interface_handle[iface].dev_handle;
+ if ((file_handle == 0) || (file_handle == INVALID_HANDLE_VALUE)) {
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ if (!WinUsb_Initialize(file_handle, &winusb_handle)) {
+ usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(0));
+ handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
+
+ switch(GetLastError()) {
+ case ERROR_BAD_COMMAND: // The device was disconnected
+ return LIBUSB_ERROR_NO_DEVICE;
+ default:
+ usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0));
+ return LIBUSB_ERROR_ACCESS;
+ }
+ }
+ handle_priv->interface_handle[iface].api_handle = winusb_handle;
+ } else {
+ // For all other interfaces, use WinUsb_GetAssociatedInterface()
+ winusb_handle = handle_priv->interface_handle[0].api_handle;
+ // It is a requirement for multiple interface devices on Windows that, to you
+ // must first claim the first interface before you claim the others
+ if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) {
+#if defined(AUTO_CLAIM)
+ file_handle = handle_priv->interface_handle[0].dev_handle;
+ if (WinUsb_Initialize(file_handle, &winusb_handle)) {
+ handle_priv->interface_handle[0].api_handle = winusb_handle;
+ usbi_warn(ctx, "auto-claimed interface 0 (required to claim %d with WinUSB)", iface);
+ } else {
+ usbi_warn(ctx, "failed to auto-claim interface 0 (required to claim %d with WinUSB)", iface);
+ return LIBUSB_ERROR_ACCESS;
+ }
+#else
+ usbi_warn(ctx, "you must claim interface 0 before you can claim %d with WinUSB", iface);
+ return LIBUSB_ERROR_ACCESS;
+#endif
+ }
+ if (!WinUsb_GetAssociatedInterface(winusb_handle, (UCHAR)(iface-1),
+ &handle_priv->interface_handle[iface].api_handle)) {
+ handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
+ switch(GetLastError()) {
+ case ERROR_NO_MORE_ITEMS: // invalid iface
+ return LIBUSB_ERROR_NOT_FOUND;
+ case ERROR_BAD_COMMAND: // The device was disconnected
+ return LIBUSB_ERROR_NO_DEVICE;
+ case ERROR_ALREADY_EXISTS: // already claimed
+ return LIBUSB_ERROR_BUSY;
+ default:
+ usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0));
+ return LIBUSB_ERROR_ACCESS;
+ }
+ }
+ }
+ usbi_dbg("claimed interface %d", iface);
+ handle_priv->active_interface = iface;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ HANDLE winusb_handle;
+
+ CHECK_WINUSB_AVAILABLE;
+
+ winusb_handle = handle_priv->interface_handle[iface].api_handle;
+ if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) {
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ WinUsb_Free(winusb_handle);
+ handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
+
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * Return the first valid interface (of the same API type), for control transfers
+ */
+static int get_valid_interface(struct libusb_device_handle *dev_handle, int api_id)
+{
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ int i;
+
+ if ((api_id < USB_API_WINUSB) || (api_id > USB_API_HID)) {
+ usbi_dbg("unsupported API ID");
+ return -1;
+ }
+
+ for (i=0; i<USB_MAXINTERFACES; i++) {
+ if ( (handle_priv->interface_handle[i].dev_handle != 0)
+ && (handle_priv->interface_handle[i].dev_handle != INVALID_HANDLE_VALUE)
+ && (handle_priv->interface_handle[i].api_handle != 0)
+ && (handle_priv->interface_handle[i].api_handle != INVALID_HANDLE_VALUE)
+ && (priv->usb_interface[i].apib->id == api_id) ) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Lookup interface by endpoint address. -1 if not found
+ */
+static int interface_by_endpoint(struct windows_device_priv *priv,
+ struct windows_device_handle_priv *handle_priv, uint8_t endpoint_address)
+{
+ int i, j;
+ for (i=0; i<USB_MAXINTERFACES; i++) {
+ if (handle_priv->interface_handle[i].api_handle == INVALID_HANDLE_VALUE)
+ continue;
+ if (handle_priv->interface_handle[i].api_handle == 0)
+ continue;
+ if (priv->usb_interface[i].endpoint == NULL)
+ continue;
+ for (j=0; j<priv->usb_interface[i].nb_endpoints; j++) {
+ if (priv->usb_interface[i].endpoint[j] == endpoint_address) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+static int winusb_submit_control_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(
+ transfer->dev_handle);
+ WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *) transfer->buffer;
+ ULONG size;
+ HANDLE winusb_handle;
+ int current_interface;
+ struct winfd wfd;
+
+ CHECK_WINUSB_AVAILABLE;
+
+ transfer_priv->pollable_fd = INVALID_WINFD;
+ size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
+
+ if (size > MAX_CTRL_BUFFER_LENGTH)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ current_interface = get_valid_interface(transfer->dev_handle, USB_API_WINUSB);
+ if (current_interface < 0) {
+#if defined(AUTO_CLAIM)
+ if (auto_claim(transfer, &current_interface, USB_API_WINUSB) != LIBUSB_SUCCESS) {
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+#else
+ usbi_warn(ctx, "no interface available for control transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+#endif
+ }
+
+ usbi_dbg("will use interface %d", current_interface);
+ winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
+
+ wfd = usbi_create_fd(winusb_handle, _O_RDONLY);
+ // Always use the handle returned from usbi_create_fd (wfd.handle)
+ if (wfd.fd < 0) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ if (!WinUsb_ControlTransfer(wfd.handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, wfd.overlapped)) {
+ if(GetLastError() != ERROR_IO_PENDING) {
+ usbi_err(ctx, "WinUsb_ControlTransfer failed: %s", windows_error_str(0));
+ usbi_free_fd(wfd.fd);
+ return LIBUSB_ERROR_IO;
+ }
+ } else {
+ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
+ wfd.overlapped->InternalHigh = (DWORD)size;
+ }
+
+ // Use priv_transfer to store data needed for async polling
+ transfer_priv->pollable_fd = wfd;
+ transfer_priv->interface_number = (uint8_t)current_interface;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ HANDLE winusb_handle;
+
+ CHECK_WINUSB_AVAILABLE;
+
+ if (altsetting > 255) {
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ winusb_handle = handle_priv->interface_handle[iface].api_handle;
+ if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) {
+ usbi_err(ctx, "interface must be claimed first");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ if (!WinUsb_SetCurrentAlternateSetting(winusb_handle, (UCHAR)altsetting)) {
+ usbi_err(ctx, "WinUsb_SetCurrentAlternateSetting failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_IO;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(transfer->dev_handle);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ HANDLE winusb_handle;
+ bool direction_in, ret;
+ int current_interface;
+ struct winfd wfd;
+
+ CHECK_WINUSB_AVAILABLE;
+
+ transfer_priv->pollable_fd = INVALID_WINFD;
+
+ current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
+
+ winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
+ direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
+
+ wfd = usbi_create_fd(winusb_handle, direction_in?_O_RDONLY:_O_WRONLY);
+ // Always use the handle returned from usbi_create_fd (wfd.handle)
+ if (wfd.fd < 0) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ if (direction_in) {
+ usbi_dbg("reading %d bytes", transfer->length);
+ ret = WinUsb_ReadPipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped);
+ } else {
+ usbi_dbg("writing %d bytes", transfer->length);
+ ret = WinUsb_WritePipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped);
+ }
+ if (!ret) {
+ if(GetLastError() != ERROR_IO_PENDING) {
+ usbi_err(ctx, "WinUsb_Pipe Transfer failed: %s", windows_error_str(0));
+ usbi_free_fd(wfd.fd);
+ return LIBUSB_ERROR_IO;
+ }
+ } else {
+ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
+ wfd.overlapped->InternalHigh = (DWORD)transfer->length;
+ }
+
+ transfer_priv->pollable_fd = wfd;
+ transfer_priv->interface_number = (uint8_t)current_interface;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ HANDLE winusb_handle;
+ int current_interface;
+
+ CHECK_WINUSB_AVAILABLE;
+
+ current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface);
+ winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
+
+ if (!WinUsb_ResetPipe(winusb_handle, endpoint)) {
+ usbi_err(ctx, "WinUsb_ResetPipe failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * from http://www.winvistatips.com/winusb-bugchecks-t335323.html (confirmed
+ * through testing as well):
+ * "You can not call WinUsb_AbortPipe on control pipe. You can possibly cancel
+ * the control transfer using CancelIo"
+ */
+static int winusb_abort_control(struct usbi_transfer *itransfer)
+{
+ // Cancelling of the I/O is done in the parent
+ return LIBUSB_SUCCESS;
+}
+
+static int winusb_abort_transfers(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(transfer->dev_handle);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ HANDLE winusb_handle;
+ int current_interface;
+
+ CHECK_WINUSB_AVAILABLE;
+
+ current_interface = transfer_priv->interface_number;
+ if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) {
+ usbi_err(ctx, "program assertion failed: invalid interface_number");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+ usbi_dbg("will use interface %d", current_interface);
+
+ winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
+
+ if (!WinUsb_AbortPipe(winusb_handle, transfer->endpoint)) {
+ usbi_err(ctx, "WinUsb_AbortPipe failed: %s", windows_error_str(0));
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+/*
+ * from the "How to Use WinUSB to Communicate with a USB Device" Microsoft white paper
+ * (http://www.microsoft.com/whdc/connect/usb/winusb_howto.mspx):
+ * "WinUSB does not support host-initiated reset port and cycle port operations" and
+ * IOCTL_INTERNAL_USB_CYCLE_PORT is only available in kernel mode and the
+ * IOCTL_USB_HUB_CYCLE_PORT ioctl was removed from Vista => the best we can do is
+ * cycle the pipes (and even then, the control pipe can not be reset using WinUSB)
+ */
+// TODO (post hotplug): see if we can force eject the device and redetect it (reuse hotplug?)
+static int winusb_reset_device(struct libusb_device_handle *dev_handle)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ struct winfd wfd;
+ HANDLE winusb_handle;
+ int i, j;
+
+ CHECK_WINUSB_AVAILABLE;
+
+ // Reset any available pipe (except control)
+ for (i=0; i<USB_MAXINTERFACES; i++) {
+ winusb_handle = handle_priv->interface_handle[i].api_handle;
+ for (wfd = handle_to_winfd(winusb_handle); wfd.fd > 0;)
+ {
+ // Cancel any pollable I/O
+ usbi_remove_pollfd(ctx, wfd.fd);
+ usbi_free_fd(wfd.fd);
+ wfd = handle_to_winfd(winusb_handle);
+ }
+
+ if ( (winusb_handle != 0) && (winusb_handle != INVALID_HANDLE_VALUE)) {
+ for (j=0; j<priv->usb_interface[i].nb_endpoints; j++) {
+ usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]);
+ if (!WinUsb_AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) {
+ usbi_err(ctx, "WinUsb_AbortPipe (pipe address %02X) failed: %s",
+ priv->usb_interface[i].endpoint[j], windows_error_str(0));
+ }
+ // FlushPipe seems to fail on OUT pipes
+ if ( (priv->usb_interface[i].endpoint[j] & LIBUSB_ENDPOINT_IN)
+ && (!WinUsb_FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) ) {
+ usbi_err(ctx, "WinUsb_FlushPipe (pipe address %02X) failed: %s",
+ priv->usb_interface[i].endpoint[j], windows_error_str(0));
+ }
+ if (!WinUsb_ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) {
+ usbi_err(ctx, "WinUsb_ResetPipe (pipe address %02X) failed: %s",
+ priv->usb_interface[i].endpoint[j], windows_error_str(0));
+ }
+ }
+ }
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusb_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
+{
+ itransfer->transferred += io_size;
+ return LIBUSB_TRANSFER_COMPLETED;
+}
+
+/*
+ * Internal HID Support functions (from libusb-win32)
+ * Note that functions that complete data transfer synchronously must return
+ * LIBUSB_COMPLETED instead of LIBUSB_SUCCESS
+ */
+static int _hid_get_hid_descriptor(struct hid_device_priv* dev, void *data, size_t *size);
+static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, size_t *size);
+
+static int _hid_wcslen(WCHAR *str)
+{
+ int i = 0;
+ while (str[i] && (str[i] != 0x409)) {
+ i++;
+ }
+ return i;
+}
+
+static int _hid_get_device_descriptor(struct hid_device_priv* dev, void *data, size_t *size)
+{
+ struct libusb_device_descriptor d;
+
+ d.bLength = LIBUSB_DT_DEVICE_SIZE;
+ d.bDescriptorType = LIBUSB_DT_DEVICE;
+ d.bcdUSB = 0x0200; /* 2.00 */
+ d.bDeviceClass = 0;
+ d.bDeviceSubClass = 0;
+ d.bDeviceProtocol = 0;
+ d.bMaxPacketSize0 = 64; /* fix this! */
+ d.idVendor = (uint16_t)dev->vid;
+ d.idProduct = (uint16_t)dev->pid;
+ d.bcdDevice = 0x0100;
+ d.iManufacturer = dev->string_index[0];
+ d.iProduct = dev->string_index[1];
+ d.iSerialNumber = dev->string_index[2];
+ d.bNumConfigurations = 1;
+
+ if (*size > LIBUSB_DT_DEVICE_SIZE)
+ *size = LIBUSB_DT_DEVICE_SIZE;
+ memcpy(data, &d, *size);
+ return LIBUSB_COMPLETED;
+}
+
+static int _hid_get_config_descriptor(struct hid_device_priv* dev, void *data, size_t *size)
+{
+ char num_endpoints = 0;
+ size_t config_total_len = 0;
+ char tmp[HID_MAX_CONFIG_DESC_SIZE];
+ struct libusb_config_descriptor *cd;
+ struct libusb_interface_descriptor *id;
+ struct libusb_hid_descriptor *hd;
+ struct libusb_endpoint_descriptor *ed;
+ size_t tmp_size;
+
+ if (dev->input_report_size)
+ num_endpoints++;
+ if (dev->output_report_size)
+ num_endpoints++;
+
+ config_total_len = LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE
+ + LIBUSB_DT_HID_SIZE + num_endpoints * LIBUSB_DT_ENDPOINT_SIZE;
+
+
+ cd = (struct libusb_config_descriptor *)tmp;
+ id = (struct libusb_interface_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE);
+ hd = (struct libusb_hid_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE
+ + LIBUSB_DT_INTERFACE_SIZE);
+ ed = (struct libusb_endpoint_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE
+ + LIBUSB_DT_INTERFACE_SIZE
+ + LIBUSB_DT_HID_SIZE);
+
+ cd->bLength = LIBUSB_DT_CONFIG_SIZE;
+ cd->bDescriptorType = LIBUSB_DT_CONFIG;
+ cd->wTotalLength = (uint16_t) config_total_len;
+ cd->bNumInterfaces = 1;
+ cd->bConfigurationValue = 1;
+ cd->iConfiguration = 0;
+ cd->bmAttributes = 1 << 7; /* bus powered */
+ cd->MaxPower = 50;
+
+ id->bLength = LIBUSB_DT_INTERFACE_SIZE;
+ id->bDescriptorType = LIBUSB_DT_INTERFACE;
+ id->bInterfaceNumber = 0;
+ id->bAlternateSetting = 0;
+ id->bNumEndpoints = num_endpoints;
+ id->bInterfaceClass = 3;
+ id->bInterfaceSubClass = 0;
+ id->bInterfaceProtocol = 0;
+ id->iInterface = 0;
+
+ tmp_size = LIBUSB_DT_HID_SIZE;
+ _hid_get_hid_descriptor(dev, hd, &tmp_size);
+
+ if (dev->input_report_size) {
+ ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
+ ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
+ ed->bEndpointAddress = HID_IN_EP;
+ ed->bmAttributes = 3;
+ ed->wMaxPacketSize = dev->input_report_size - 1;
+ ed->bInterval = 10;
+
+ ed++;
+ }
+
+ if (dev->output_report_size) {
+ ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
+ ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
+ ed->bEndpointAddress = HID_OUT_EP;
+ ed->bmAttributes = 3;
+ ed->wMaxPacketSize = dev->output_report_size - 1;
+ ed->bInterval = 10;
+ }
+
+ if (*size > config_total_len)
+ *size = config_total_len;
+ memcpy(data, tmp, *size);
+ return LIBUSB_COMPLETED;
+}
+
+static int _hid_get_string_descriptor(struct hid_device_priv* dev, int _index,
+ void *data, size_t *size)
+{
+ void *tmp = NULL;
+ size_t tmp_size = 0;
+ int i;
+
+ /* language ID, EN-US */
+ char string_langid[] = {
+ 0x09,
+ 0x04
+ };
+
+ if ((*size < 2) || (*size > 255)) {
+ return LIBUSB_ERROR_OVERFLOW;
+ }
+
+ if (_index == 0) {
+ tmp = string_langid;
+ tmp_size = sizeof(string_langid)+2;
+ } else {
+ for (i=0; i<3; i++) {
+ if (_index == (dev->string_index[i])) {
+ tmp = dev->string[i];
+ tmp_size = (_hid_wcslen(dev->string[i])+1) * sizeof(WCHAR);
+ break;
+ }
+ }
+ if (i == 3) { // not found
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+ }
+
+ if(!tmp_size) {
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ if (tmp_size < *size) {
+ *size = tmp_size;
+ }
+ // 2 byte header
+ ((uint8_t*)data)[0] = (uint8_t)*size;
+ ((uint8_t*)data)[1] = LIBUSB_DT_STRING;
+ memcpy((uint8_t*)data+2, tmp, *size-2);
+ return LIBUSB_COMPLETED;
+}
+
+static int _hid_get_hid_descriptor(struct hid_device_priv* dev, void *data, size_t *size)
+{
+ struct libusb_hid_descriptor d;
+ uint8_t tmp[MAX_HID_DESCRIPTOR_SIZE];
+ size_t report_len = MAX_HID_DESCRIPTOR_SIZE;
+
+ _hid_get_report_descriptor(dev, tmp, &report_len);
+
+ d.bLength = LIBUSB_DT_HID_SIZE;
+ d.bDescriptorType = LIBUSB_DT_HID;
+ d.bcdHID = 0x0110; /* 1.10 */
+ d.bCountryCode = 0;
+ d.bNumDescriptors = 1;
+ d.bClassDescriptorType = LIBUSB_DT_REPORT;
+ d.wClassDescriptorLength = (uint16_t)report_len;
+
+ if (*size > LIBUSB_DT_HID_SIZE)
+ *size = LIBUSB_DT_HID_SIZE;
+ memcpy(data, &d, *size);
+ return LIBUSB_COMPLETED;
+}
+
+static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, size_t *size)
+{
+ uint8_t d[MAX_HID_DESCRIPTOR_SIZE];
+ size_t i = 0;
+
+ /* usage page (0xFFA0 == vendor defined) */
+ d[i++] = 0x06; d[i++] = 0xA0; d[i++] = 0xFF;
+ /* usage (vendor defined) */
+ d[i++] = 0x09; d[i++] = 0x01;
+ /* start collection (application) */
+ d[i++] = 0xA1; d[i++] = 0x01;
+ /* input report */
+ if (dev->input_report_size) {
+ /* usage (vendor defined) */
+ d[i++] = 0x09; d[i++] = 0x01;
+ /* logical minimum (0) */
+ d[i++] = 0x15; d[i++] = 0x00;
+ /* logical maximum (255) */
+ d[i++] = 0x25; d[i++] = 0xFF;
+ /* report size (8 bits) */
+ d[i++] = 0x75; d[i++] = 0x08;
+ /* report count */
+ d[i++] = 0x95; d[i++] = (uint8_t)dev->input_report_size - 1;
+ /* input (data, variable, absolute) */
+ d[i++] = 0x81; d[i++] = 0x00;
+ }
+ /* output report */
+ if (dev->output_report_size) {
+ /* usage (vendor defined) */
+ d[i++] = 0x09; d[i++] = 0x02;
+ /* logical minimum (0) */
+ d[i++] = 0x15; d[i++] = 0x00;
+ /* logical maximum (255) */
+ d[i++] = 0x25; d[i++] = 0xFF;
+ /* report size (8 bits) */
+ d[i++] = 0x75; d[i++] = 0x08;
+ /* report count */
+ d[i++] = 0x95; d[i++] = (uint8_t)dev->output_report_size - 1;
+ /* output (data, variable, absolute) */
+ d[i++] = 0x91; d[i++] = 0x00;
+ }
+ /* feature report */
+ if (dev->feature_report_size) {
+ /* usage (vendor defined) */
+ d[i++] = 0x09; d[i++] = 0x03;
+ /* logical minimum (0) */
+ d[i++] = 0x15; d[i++] = 0x00;
+ /* logical maximum (255) */
+ d[i++] = 0x25; d[i++] = 0xFF;
+ /* report size (8 bits) */
+ d[i++] = 0x75; d[i++] = 0x08;
+ /* report count */
+ d[i++] = 0x95; d[i++] = (uint8_t)dev->feature_report_size - 1;
+ /* feature (data, variable, absolute) */
+ d[i++] = 0xb2; d[i++] = 0x02; d[i++] = 0x01;
+ }
+
+ /* end collection */
+ d[i++] = 0xC0;
+
+ if (*size > i)
+ *size = i;
+ memcpy(data, d, *size);
+ return LIBUSB_COMPLETED;
+}
+
+static int _hid_get_descriptor(struct hid_device_priv* dev, HANDLE hid_handle, int recipient,
+ int type, int _index, void *data, size_t *size)
+{
+ switch(type) {
+ case LIBUSB_DT_DEVICE:
+ usbi_dbg("LIBUSB_DT_DEVICE");
+ return _hid_get_device_descriptor(dev, data, size);
+ case LIBUSB_DT_CONFIG:
+ usbi_dbg("LIBUSB_DT_CONFIG");
+ if (!_index)
+ return _hid_get_config_descriptor(dev, data, size);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ case LIBUSB_DT_STRING:
+ usbi_dbg("LIBUSB_DT_STRING");
+ return _hid_get_string_descriptor(dev, _index, data, size);
+ case LIBUSB_DT_HID:
+ usbi_dbg("LIBUSB_DT_HID");
+ if (!_index)
+ return _hid_get_hid_descriptor(dev, data, size);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ case LIBUSB_DT_REPORT:
+ usbi_dbg("LIBUSB_DT_REPORT");
+ if (!_index)
+ return _hid_get_report_descriptor(dev, data, size);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ case LIBUSB_DT_PHYSICAL:
+ usbi_dbg("LIBUSB_DT_PHYSICAL");
+ if (HidD_GetPhysicalDescriptor(hid_handle, data, (ULONG)*size))
+ return LIBUSB_COMPLETED;
+ return LIBUSB_ERROR_OTHER;
+ }
+ usbi_dbg("unsupported");
+ return LIBUSB_ERROR_INVALID_PARAM;
+}
+
+static int _hid_get_report(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data,
+ struct windows_transfer_priv *tp, size_t *size, OVERLAPPED* overlapped,
+ int report_type)
+{
+ uint8_t *buf;
+ DWORD ioctl_code, read_size, expected_size = (DWORD)*size;
+ int r = LIBUSB_SUCCESS;
+
+ if (tp->hid_buffer != NULL) {
+ usbi_dbg("program assertion failed: hid_buffer is not NULL");
+ }
+
+ if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) {
+ usbi_dbg("invalid size (%d)", *size);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ switch (report_type) {
+ case HID_REPORT_TYPE_INPUT:
+ ioctl_code = IOCTL_HID_GET_INPUT_REPORT;
+ break;
+ case HID_REPORT_TYPE_FEATURE:
+ ioctl_code = IOCTL_HID_GET_FEATURE;
+ break;
+ default:
+ usbi_dbg("unknown HID report type %d", report_type);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ // Add a trailing byte to detect overflows
+ buf = (uint8_t*)calloc(expected_size+1, 1);
+ if (buf == NULL) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+ buf[0] = (uint8_t)id; // Must be set always
+ usbi_dbg("report ID: 0x%02X", buf[0]);
+
+ tp->hid_expected_size = expected_size;
+ read_size = expected_size;
+
+ // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
+ if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size+1,
+ buf, expected_size+1, &read_size, overlapped)) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ usbi_dbg("Failed to Read HID Report: %s", windows_error_str(0));
+ safe_free(buf);
+ return LIBUSB_ERROR_IO;
+ }
+ // Asynchronous wait
+ tp->hid_buffer = buf;
+ tp->hid_dest = data; // copy dest, as not necessarily the start of the transfer buffer
+ return LIBUSB_SUCCESS;
+ }
+
+ // Transfer completed synchronously => copy and discard extra buffer
+ if (read_size == 0) {
+ usbi_warn(NULL, "program assertion failed - read completed synchronously, but no data was read");
+ *size = 0;
+ } else {
+ if (buf[0] != id) {
+ usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id);
+ }
+ if ((size_t)read_size > expected_size) {
+ r = LIBUSB_ERROR_OVERFLOW;
+ usbi_dbg("OVERFLOW!");
+ } else {
+ r = LIBUSB_COMPLETED;
+ }
+
+ *size = MIN((size_t)read_size, *size);
+ if (id == 0) {
+ // Discard report ID
+ memcpy(data, buf+1, *size);
+ } else {
+ memcpy(data, buf, *size);
+ }
+ }
+ safe_free(buf);
+ return r;
+}
+
+static int _hid_set_report(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data,
+ struct windows_transfer_priv *tp, size_t *size, OVERLAPPED* overlapped,
+ int report_type)
+{
+ uint8_t *buf = NULL;
+ DWORD ioctl_code, write_size= (DWORD)*size;
+
+ if (tp->hid_buffer != NULL) {
+ usbi_dbg("program assertion failed: hid_buffer is not NULL");
+ }
+
+ if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) {
+ usbi_dbg("invalid size (%d)", *size);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ switch (report_type) {
+ case HID_REPORT_TYPE_OUTPUT:
+ ioctl_code = IOCTL_HID_SET_OUTPUT_REPORT;
+ break;
+ case HID_REPORT_TYPE_FEATURE:
+ ioctl_code = IOCTL_HID_SET_FEATURE;
+ break;
+ default:
+ usbi_dbg("unknown HID report type %d", report_type);
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ usbi_dbg("report ID: 0x%02X", id);
+ // When report IDs are not used (i.e. when id == 0), we must add
+ // a null report ID. Otherwise, we just use original data buffer
+ if (id == 0) {
+ write_size++;
+ }
+ buf = malloc(write_size);
+ if (buf == NULL) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+ if (id == 0) {
+ buf[0] = 0;
+ memcpy(buf + 1, data, *size);
+ } else {
+ // This seems like a waste, but if we don't duplicate the
+ // data, we'll get issues when freeing hid_buffer
+ memcpy(buf, data, *size);
+ if (buf[0] != id) {
+ usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id);
+ }
+ }
+
+ // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
+ if (!DeviceIoControl(hid_handle, ioctl_code, buf, write_size,
+ buf, write_size, &write_size, overlapped)) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ usbi_dbg("Failed to Write HID Output Report: %s", windows_error_str(0));
+ safe_free(buf);
+ return LIBUSB_ERROR_IO;
+ }
+ tp->hid_buffer = buf;
+ tp->hid_dest = NULL;
+ return LIBUSB_SUCCESS;
+ }
+
+ // Transfer completed synchronously
+ *size = write_size;
+ if (write_size == 0) {
+ usbi_dbg("program assertion failed - write completed synchronously, but no data was written");
+ }
+ safe_free(buf);
+ return LIBUSB_COMPLETED;
+}
+
+static int _hid_class_request(struct hid_device_priv* dev, HANDLE hid_handle, int request_type,
+ int request, int value, int _index, void *data, struct windows_transfer_priv *tp,
+ size_t *size, OVERLAPPED* overlapped)
+{
+ int report_type = (value >> 8) & 0xFF;
+ int report_id = value & 0xFF;
+
+ if ( (LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_INTERFACE)
+ && (LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_DEVICE) )
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ if (LIBUSB_REQ_OUT(request_type) && request == HID_REQ_SET_REPORT)
+ return _hid_set_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type);
+
+ if (LIBUSB_REQ_IN(request_type) && request == HID_REQ_GET_REPORT)
+ return _hid_get_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type);
+
+ return LIBUSB_ERROR_INVALID_PARAM;
+}
+
+
+/*
+ * HID API functions
+ */
+static int hid_init(struct libusb_context *ctx)
+{
+ DLL_LOAD(hid.dll, HidD_GetAttributes, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetHidGuid, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetPreparsedData, TRUE);
+ DLL_LOAD(hid.dll, HidD_FreePreparsedData, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetManufacturerString, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetProductString, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetSerialNumberString, TRUE);
+ DLL_LOAD(hid.dll, HidP_GetCaps, TRUE);
+ DLL_LOAD(hid.dll, HidD_SetNumInputBuffers, TRUE);
+ DLL_LOAD(hid.dll, HidD_SetFeature, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetFeature, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetPhysicalDescriptor, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetInputReport, FALSE);
+ DLL_LOAD(hid.dll, HidD_SetOutputReport, FALSE);
+ DLL_LOAD(hid.dll, HidD_FlushQueue, TRUE);
+ DLL_LOAD(hid.dll, HidP_GetValueCaps, TRUE);
+
+ api_hid_available = true;
+ return LIBUSB_SUCCESS;
+}
+
+static int hid_exit(void)
+{
+ return LIBUSB_SUCCESS;
+}
+
+// NB: open and close must ensure that they only handle interface of
+// the right API type, as these functions can be called wholesale from
+// composite_open(), with interfaces belonging to different APIs
+static int hid_open(struct libusb_device_handle *dev_handle)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+
+ HIDD_ATTRIBUTES hid_attributes;
+ PHIDP_PREPARSED_DATA preparsed_data = NULL;
+ HIDP_CAPS capabilities;
+ HIDP_VALUE_CAPS *value_caps;
+
+ HANDLE hid_handle = INVALID_HANDLE_VALUE;
+ int i, j;
+ // report IDs handling
+ ULONG size[3];
+ char* type[3] = {"input", "output", "feature"};
+ int nb_ids[2]; // zero and nonzero report IDs
+
+ CHECK_HID_AVAILABLE;
+ if (priv->hid == NULL) {
+ usbi_err(ctx, "program assertion failed - private HID structure is unitialized");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if ( (priv->usb_interface[i].path != NULL)
+ && (priv->usb_interface[i].apib->id == USB_API_HID) ) {
+ hid_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+ /*
+ * http://www.lvr.com/hidfaq.htm: Why do I receive "Access denied" when attempting to access my HID?
+ * "Windows 2000 and later have exclusive read/write access to HIDs that are configured as a system
+ * keyboards or mice. An application can obtain a handle to a system keyboard or mouse by not
+ * requesting READ or WRITE access with CreateFile. Applications can then use HidD_SetFeature and
+ * HidD_GetFeature (if the device supports Feature reports)."
+ */
+ if (hid_handle == INVALID_HANDLE_VALUE) {
+ usbi_warn(ctx, "could not open HID device in R/W mode (keyboard or mouse?) - trying without");
+ hid_handle = CreateFileA(priv->usb_interface[i].path, 0, FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+ if (hid_handle == INVALID_HANDLE_VALUE) {
+ usbi_err(ctx, "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0));
+ switch(GetLastError()) {
+ case ERROR_FILE_NOT_FOUND: // The device was disconnected
+ return LIBUSB_ERROR_NO_DEVICE;
+ case ERROR_ACCESS_DENIED:
+ return LIBUSB_ERROR_ACCESS;
+ default:
+ return LIBUSB_ERROR_IO;
+ }
+ }
+ priv->usb_interface[i].restricted_functionality = true;
+ }
+ handle_priv->interface_handle[i].api_handle = hid_handle;
+ }
+ }
+
+ hid_attributes.Size = sizeof(hid_attributes);
+ do {
+ if (!HidD_GetAttributes(hid_handle, &hid_attributes)) {
+ usbi_err(ctx, "could not gain access to HID top collection (HidD_GetAttributes)");
+ break;
+ }
+
+ priv->hid->vid = hid_attributes.VendorID;
+ priv->hid->pid = hid_attributes.ProductID;
+
+ // Set the maximum available input buffer size
+ for (i=32; HidD_SetNumInputBuffers(hid_handle, i); i*=2);
+ usbi_dbg("set maximum input buffer size to %d", i/2);
+
+ // Get the maximum input and output report size
+ if (!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) {
+ usbi_err(ctx, "could not read HID preparsed data (HidD_GetPreparsedData)");
+ break;
+ }
+ if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) {
+ usbi_err(ctx, "could not parse HID capabilities (HidP_GetCaps)");
+ break;
+ }
+
+ // Find out if interrupt will need report IDs
+ size[0] = capabilities.NumberInputValueCaps;
+ size[1] = capabilities.NumberOutputValueCaps;
+ size[2] = capabilities.NumberFeatureValueCaps;
+ for (j=0; j<3; j++) {
+ usbi_dbg("%d HID %s report value(s) found", size[j], type[j]);
+ priv->hid->uses_report_ids[j] = false;
+ if (size[j] > 0) {
+ value_caps = malloc(size[j] * sizeof(HIDP_VALUE_CAPS));
+ if ( (value_caps != NULL)
+ && (HidP_GetValueCaps(j, value_caps, &size[j], preparsed_data) == HIDP_STATUS_SUCCESS)
+ && (size[j] >= 1) ) {
+ nb_ids[0] = 0;
+ nb_ids[1] = 0;
+ for (i=0; i<(int)size[j]; i++) {
+ usbi_dbg(" Report ID: 0x%02X", value_caps[i].ReportID);
+ if (value_caps[i].ReportID != 0) {
+ nb_ids[1]++;
+ } else {
+ nb_ids[0]++;
+ }
+ }
+ if (nb_ids[1] != 0) {
+ if (nb_ids[0] != 0) {
+ usbi_warn(ctx, "program assertion failed: zero and nonzero report IDs used for %s",
+ type[j]);
+ }
+ priv->hid->uses_report_ids[j] = true;
+ }
+ } else {
+ usbi_warn(ctx, " could not process %s report IDs", type[j]);
+ }
+ safe_free(value_caps);
+ }
+ }
+
+ // Set the report sizes
+ priv->hid->input_report_size = capabilities.InputReportByteLength;
+ priv->hid->output_report_size = capabilities.OutputReportByteLength;
+ priv->hid->feature_report_size = capabilities.FeatureReportByteLength;
+
+ // Fetch string descriptors
+ priv->hid->string_index[0] = priv->dev_descriptor.iManufacturer;
+ if (priv->hid->string_index[0] != 0) {
+ HidD_GetManufacturerString(hid_handle, priv->hid->string[0],
+ sizeof(priv->hid->string[0]));
+ } else {
+ priv->hid->string[0][0] = 0;
+ }
+ priv->hid->string_index[1] = priv->dev_descriptor.iProduct;
+ if (priv->hid->string_index[1] != 0) {
+ HidD_GetProductString(hid_handle, priv->hid->string[1],
+ sizeof(priv->hid->string[1]));
+ } else {
+ priv->hid->string[1][0] = 0;
+ }
+ priv->hid->string_index[2] = priv->dev_descriptor.iSerialNumber;
+ if (priv->hid->string_index[2] != 0) {
+ HidD_GetSerialNumberString(hid_handle, priv->hid->string[2],
+ sizeof(priv->hid->string[2]));
+ } else {
+ priv->hid->string[2][0] = 0;
+ }
+ } while(0);
+
+ if (preparsed_data) {
+ HidD_FreePreparsedData(preparsed_data);
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static void hid_close(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ HANDLE file_handle;
+ int i;
+
+ if (!api_hid_available)
+ return;
+
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if (priv->usb_interface[i].apib->id == USB_API_HID) {
+ file_handle = handle_priv->interface_handle[i].api_handle;
+ if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) {
+ CloseHandle(file_handle);
+ }
+ }
+ }
+}
+
+static int hid_claim_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+
+ CHECK_HID_AVAILABLE;
+
+ // NB: Disconnection detection is not possible in this function
+ if (priv->usb_interface[iface].path == NULL) {
+ return LIBUSB_ERROR_NOT_FOUND; // invalid iface
+ }
+
+ // We use dev_handle as a flag for interface claimed
+ if (handle_priv->interface_handle[iface].dev_handle == INTERFACE_CLAIMED) {
+ return LIBUSB_ERROR_BUSY; // already claimed
+ }
+
+ handle_priv->interface_handle[iface].dev_handle = INTERFACE_CLAIMED;
+
+ usbi_dbg("claimed interface %d", iface);
+ handle_priv->active_interface = iface;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int hid_release_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+
+ CHECK_HID_AVAILABLE;
+
+ if (priv->usb_interface[iface].path == NULL) {
+ return LIBUSB_ERROR_NOT_FOUND; // invalid iface
+ }
+
+ if (handle_priv->interface_handle[iface].dev_handle != INTERFACE_CLAIMED) {
+ return LIBUSB_ERROR_NOT_FOUND; // invalid iface
+ }
+
+ handle_priv->interface_handle[iface].dev_handle = INVALID_HANDLE_VALUE;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int hid_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+
+ CHECK_HID_AVAILABLE;
+
+ if (altsetting > 255) {
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ if (altsetting != 0) {
+ usbi_err(ctx, "set interface altsetting not supported for altsetting >0");
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static int hid_submit_control_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(transfer->dev_handle);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *) transfer->buffer;
+ HANDLE hid_handle;
+ struct winfd wfd;
+ int current_interface, config;
+ size_t size;
+ int r = LIBUSB_ERROR_INVALID_PARAM;
+
+ CHECK_HID_AVAILABLE;
+
+ transfer_priv->pollable_fd = INVALID_WINFD;
+ safe_free(transfer_priv->hid_buffer);
+ transfer_priv->hid_dest = NULL;
+ size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
+
+ if (size > MAX_CTRL_BUFFER_LENGTH) {
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ current_interface = get_valid_interface(transfer->dev_handle, USB_API_HID);
+ if (current_interface < 0) {
+#if defined(AUTO_CLAIM)
+ if (auto_claim(transfer, &current_interface, USB_API_HID) != LIBUSB_SUCCESS) {
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+#else
+ usbi_warn(ctx, "no interface available for control transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+#endif
+ }
+
+ usbi_dbg("will use interface %d", current_interface);
+ hid_handle = handle_priv->interface_handle[current_interface].api_handle;
+ // Always use the handle returned from usbi_create_fd (wfd.handle)
+ wfd = usbi_create_fd(hid_handle, _O_RDONLY);
+ if (wfd.fd < 0) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ switch(LIBUSB_REQ_TYPE(setup->request_type)) {
+ case LIBUSB_REQUEST_TYPE_STANDARD:
+ switch(setup->request) {
+ case LIBUSB_REQUEST_GET_DESCRIPTOR:
+ r = _hid_get_descriptor(priv->hid, wfd.handle, LIBUSB_REQ_RECIPIENT(setup->request_type),
+ (setup->value >> 8) & 0xFF, setup->value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size);
+ break;
+ case LIBUSB_REQUEST_GET_CONFIGURATION:
+ r = windows_get_configuration(transfer->dev_handle, &config);
+ if (r == LIBUSB_SUCCESS) {
+ size = 1;
+ ((uint8_t*)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = (uint8_t)config;
+ r = LIBUSB_COMPLETED;
+ }
+ break;
+ case LIBUSB_REQUEST_SET_CONFIGURATION:
+ if (setup->value == priv->active_config) {
+ r = LIBUSB_COMPLETED;
+ } else {
+ usbi_warn(ctx, "cannot set configuration other than the default one");
+ r = LIBUSB_ERROR_INVALID_PARAM;
+ }
+ break;
+ case LIBUSB_REQUEST_GET_INTERFACE:
+ size = 1;
+ ((uint8_t*)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = 0;
+ r = LIBUSB_COMPLETED;
+ break;
+ case LIBUSB_REQUEST_SET_INTERFACE:
+ r = hid_set_interface_altsetting(transfer->dev_handle, setup->index, setup->value);
+ if (r == LIBUSB_SUCCESS) {
+ r = LIBUSB_COMPLETED;
+ }
+ break;
+ default:
+ usbi_warn(ctx, "unsupported HID control request");
+ r = LIBUSB_ERROR_INVALID_PARAM;
+ break;
+ }
+ break;
+ case LIBUSB_REQUEST_TYPE_CLASS:
+ r =_hid_class_request(priv->hid, wfd.handle, setup->request_type, setup->request, setup->value,
+ setup->index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv,
+ &size, wfd.overlapped);
+ break;
+ default:
+ usbi_warn(ctx, "unsupported HID control request");
+ r = LIBUSB_ERROR_INVALID_PARAM;
+ break;
+ }
+
+ if (r == LIBUSB_COMPLETED) {
+ // Force request to be completed synchronously. Transferred size has been set by previous call
+ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
+ // http://msdn.microsoft.com/en-us/library/ms684342%28VS.85%29.aspx
+ // set InternalHigh to the number of bytes transferred
+ wfd.overlapped->InternalHigh = (DWORD)size;
+ r = LIBUSB_SUCCESS;
+ }
+
+ if (r == LIBUSB_SUCCESS) {
+ // Use priv_transfer to store data needed for async polling
+ transfer_priv->pollable_fd = wfd;
+ transfer_priv->interface_number = (uint8_t)current_interface;
+ } else {
+ usbi_free_fd(wfd.fd);
+ }
+
+ return r;
+}
+
+static int hid_submit_bulk_transfer(struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(transfer->dev_handle);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ struct winfd wfd;
+ HANDLE hid_handle;
+ bool direction_in, ret;
+ int current_interface, length;
+ DWORD size;
+ int r = LIBUSB_SUCCESS;
+
+ CHECK_HID_AVAILABLE;
+
+ transfer_priv->pollable_fd = INVALID_WINFD;
+ transfer_priv->hid_dest = NULL;
+ safe_free(transfer_priv->hid_buffer);
+
+ current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
+
+ hid_handle = handle_priv->interface_handle[current_interface].api_handle;
+ direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
+
+ wfd = usbi_create_fd(hid_handle, direction_in?_O_RDONLY:_O_WRONLY);
+ // Always use the handle returned from usbi_create_fd (wfd.handle)
+ if (wfd.fd < 0) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ // If report IDs are not in use, an extra prefix byte must be added
+ if ( ((direction_in) && (!priv->hid->uses_report_ids[0]))
+ || ((!direction_in) && (!priv->hid->uses_report_ids[1])) ) {
+ length = transfer->length+1;
+ } else {
+ length = transfer->length;
+ }
+ // Add a trailing byte to detect overflows on input
+ transfer_priv->hid_buffer = (uint8_t*)calloc(length+1, 1);
+ if (transfer_priv->hid_buffer == NULL) {
+ return LIBUSB_ERROR_NO_MEM;
+ }
+ transfer_priv->hid_expected_size = length;
+
+ if (direction_in) {
+ transfer_priv->hid_dest = transfer->buffer;
+ usbi_dbg("reading %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]);
+ ret = ReadFile(wfd.handle, transfer_priv->hid_buffer, length+1, &size, wfd.overlapped);
+ } else {
+ if (!priv->hid->uses_report_ids[1]) {
+ memcpy(transfer_priv->hid_buffer+1, transfer->buffer, transfer->length);
+ } else {
+ // We could actually do without the calloc and memcpy in this case
+ memcpy(transfer_priv->hid_buffer, transfer->buffer, transfer->length);
+ }
+ usbi_dbg("writing %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]);
+ ret = WriteFile(wfd.handle, transfer_priv->hid_buffer, length, &size, wfd.overlapped);
+ }
+ if (!ret) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ usbi_err(ctx, "HID transfer failed: %s", windows_error_str(0));
+ usbi_free_fd(wfd.fd);
+ safe_free(transfer_priv->hid_buffer);
+ return LIBUSB_ERROR_IO;
+ }
+ } else {
+ // Only write operations that completed synchronously need to free up
+ // hid_buffer. For reads, copy_transfer_data() handles that process.
+ if (!direction_in) {
+ safe_free(transfer_priv->hid_buffer);
+ }
+ if (size == 0) {
+ usbi_err(ctx, "program assertion failed - no data was transferred");
+ size = 1;
+ }
+ if (size > (size_t)length) {
+ usbi_err(ctx, "OVERFLOW!");
+ r = LIBUSB_ERROR_OVERFLOW;
+ }
+ wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
+ wfd.overlapped->InternalHigh = size;
+ }
+
+ transfer_priv->pollable_fd = wfd;
+ transfer_priv->interface_number = (uint8_t)current_interface;
+
+ return r;
+}
+
+static int hid_abort_transfers(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(transfer->dev_handle);
+ HANDLE hid_handle;
+ int current_interface;
+
+ CHECK_HID_AVAILABLE;
+
+ current_interface = transfer_priv->interface_number;
+ hid_handle = handle_priv->interface_handle[current_interface].api_handle;
+ CancelIo(hid_handle);
+
+ return LIBUSB_SUCCESS;
+}
+
+static int hid_reset_device(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ HANDLE hid_handle;
+ int current_interface;
+
+ CHECK_HID_AVAILABLE;
+
+ // Flushing the queues on all interfaces is the best we can achieve
+ for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) {
+ hid_handle = handle_priv->interface_handle[current_interface].api_handle;
+ if ((hid_handle != 0) && (hid_handle != INVALID_HANDLE_VALUE)) {
+ HidD_FlushQueue(hid_handle);
+ }
+ }
+ return LIBUSB_SUCCESS;
+}
+
+static int hid_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ HANDLE hid_handle;
+ int current_interface;
+
+ CHECK_HID_AVAILABLE;
+
+ current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface);
+ hid_handle = handle_priv->interface_handle[current_interface].api_handle;
+
+ // No endpoint selection with Microsoft's implementation, so we try to flush the
+ // whole interface. Should be OK for most case scenarios
+ if (!HidD_FlushQueue(hid_handle)) {
+ usbi_err(ctx, "Flushing of HID queue failed: %s", windows_error_str(0));
+ // Device was probably disconnected
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+// This extra function is only needed for HID
+static int hid_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ int r = LIBUSB_TRANSFER_COMPLETED;
+ uint32_t corrected_size = io_size;
+
+ if (transfer_priv->hid_buffer != NULL) {
+ // If we have a valid hid_buffer, it means the transfer was async
+ if (transfer_priv->hid_dest != NULL) { // Data readout
+ // First, check for overflow
+ if (corrected_size > transfer_priv->hid_expected_size) {
+ usbi_err(ctx, "OVERFLOW!");
+ corrected_size = (uint32_t)transfer_priv->hid_expected_size;
+ r = LIBUSB_TRANSFER_OVERFLOW;
+ }
+
+ if (transfer_priv->hid_buffer[0] == 0) {
+ // Discard the 1 byte report ID prefix
+ corrected_size--;
+ memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer+1, corrected_size);
+ } else {
+ memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, corrected_size);
+ }
+ transfer_priv->hid_dest = NULL;
+ }
+ // For write, we just need to free the hid buffer
+ safe_free(transfer_priv->hid_buffer);
+ }
+ itransfer->transferred += corrected_size;
+ return r;
+}
+
+
+/*
+ * Composite API functions
+ */
+static int composite_init(struct libusb_context *ctx)
+{
+ return LIBUSB_SUCCESS;
+}
+
+static int composite_exit(void)
+{
+ return LIBUSB_SUCCESS;
+}
+
+static int composite_open(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ unsigned api;
+ int r;
+ uint8_t flag = 1<<USB_API_WINUSB;
+
+ for (api=USB_API_WINUSB; api<USB_API_MAX; api++) {
+ if (priv->composite_api_flags & flag) {
+ r = usb_api_backend[api].open(dev_handle);
+ if (r != LIBUSB_SUCCESS) {
+ return r;
+ }
+ }
+ flag <<= 1;
+ }
+ return LIBUSB_SUCCESS;
+}
+
+static void composite_close(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ unsigned api;
+ uint8_t flag = 1<<USB_API_WINUSB;
+
+ for (api=USB_API_WINUSB; api<USB_API_MAX; api++) {
+ if (priv->composite_api_flags & flag) {
+ usb_api_backend[api].close(dev_handle);
+ }
+ flag <<= 1;
+ }
+}
+
+static int composite_claim_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ return priv->usb_interface[iface].apib->claim_interface(dev_handle, iface);
+}
+
+static int composite_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ return priv->usb_interface[iface].apib->set_interface_altsetting(dev_handle, iface, altsetting);
+}
+
+static int composite_release_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ return priv->usb_interface[iface].apib->release_interface(dev_handle, iface);
+}
+
+static int composite_submit_control_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ int i, pass;
+
+ // Interface shouldn't matter for control, but it does in practice, with Windows'
+ // restrictions with regards to accessing HID keyboards and mice. Try a 2 pass approach
+ for (pass = 0; pass < 2; pass++) {
+ for (i=0; i<USB_MAXINTERFACES; i++) {
+ if (priv->usb_interface[i].path != NULL) {
+ if ((pass == 0) && (priv->usb_interface[i].restricted_functionality)) {
+ usbi_dbg("trying to skip restricted interface #%d (HID keyboard or mouse?)", i);
+ continue;
+ }
+ usbi_dbg("using interface %d", i);
+ return priv->usb_interface[i].apib->submit_control_transfer(itransfer);
+ }
+ }
+ }
+
+ usbi_err(ctx, "no libusb supported interfaces to complete request");
+ return LIBUSB_ERROR_NOT_FOUND;
+}
+
+static int composite_submit_bulk_transfer(struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(transfer->dev_handle);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ int current_interface;
+
+ current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ return priv->usb_interface[current_interface].apib->submit_bulk_transfer(itransfer);
+}
+
+static int composite_submit_iso_transfer(struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(transfer->dev_handle);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ int current_interface;
+
+ current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ return priv->usb_interface[current_interface].apib->submit_iso_transfer(itransfer);
+}
+
+static int composite_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ int current_interface;
+
+ current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ return priv->usb_interface[current_interface].apib->clear_halt(dev_handle, endpoint);
+}
+
+static int composite_abort_control(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+
+ return priv->usb_interface[transfer_priv->interface_number].apib->abort_control(itransfer);
+}
+
+static int composite_abort_transfers(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+
+ return priv->usb_interface[transfer_priv->interface_number].apib->abort_transfers(itransfer);
+}
+
+static int composite_reset_device(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ unsigned api;
+ int r;
+ uint8_t flag = 1<<USB_API_WINUSB;
+
+ for (api=USB_API_WINUSB; api<USB_API_MAX; api++) {
+ if (priv->composite_api_flags & flag) {
+ r = usb_api_backend[api].reset_device(dev_handle);
+ if (r != LIBUSB_SUCCESS) {
+ return r;
+ }
+ }
+ flag <<= 1;
+ }
+ return LIBUSB_SUCCESS;
+}
+
+static int composite_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+
+ return priv->usb_interface[transfer_priv->interface_number].apib->copy_transfer_data(itransfer, io_size);
+}
diff --git a/libusb-1.0/libusb/os/windows_usb.h b/libusb-1.0/libusb/os/windows_usb.h
new file mode 100644
index 0000000..8851f41
--- /dev/null
+++ b/libusb-1.0/libusb/os/windows_usb.h
@@ -0,0 +1,784 @@
+/*
+ * Windows backend for libusb 1.0
+ * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com>
+ * With contributions from Michael Plante, Orin Eman et al.
+ * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
+ * Major code testing contribution by Xiaofan Chen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#if defined(_MSC_VER)
+// disable /W4 MSVC warnings that are benign
+#pragma warning(disable:4127) // conditional expression is constant
+#pragma warning(disable:4100) // unreferenced formal parameter
+#pragma warning(disable:4214) // bit field types other than int
+#pragma warning(disable:4201) // nameless struct/union
+#endif
+
+// Windows API default is uppercase - ugh!
+#if !defined(bool)
+#define bool BOOL
+#endif
+#if !defined(true)
+#define true TRUE
+#endif
+#if !defined(false)
+#define false FALSE
+#endif
+
+// Missing from MSVC6 setupapi.h
+#if !defined(SPDRP_ADDRESS)
+#define SPDRP_ADDRESS 28
+#endif
+#if !defined(SPDRP_INSTALL_STATE)
+#define SPDRP_INSTALL_STATE 34
+#endif
+
+#if defined(__CYGWIN__ )
+// cygwin produces a warning unless these prototypes are defined
+extern int _snprintf(char *buffer, size_t count, const char *format, ...);
+extern char *_strdup(const char *strSource);
+// _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread
+#define _beginthreadex(a, b, c, d, e, f) CreateThread(a, b, (LPTHREAD_START_ROUTINE)c, d, e, f)
+#endif
+#define safe_free(p) do {if (p != NULL) {free((void*)p); p = NULL;}} while(0)
+#define safe_closehandle(h) do {if (h != INVALID_HANDLE_VALUE) {CloseHandle(h); h = INVALID_HANDLE_VALUE;}} while(0)
+#define safe_min(a, b) min((size_t)(a), (size_t)(b))
+#define safe_strcp(dst, dst_max, src, count) do {memcpy(dst, src, safe_min(count, dst_max)); \
+ ((char*)dst)[safe_min(count, dst_max)-1] = 0;} while(0)
+#define safe_strcpy(dst, dst_max, src) safe_strcp(dst, dst_max, src, safe_strlen(src)+1)
+#define safe_strncat(dst, dst_max, src, count) strncat(dst, src, safe_min(count, dst_max - safe_strlen(dst) - 1))
+#define safe_strcat(dst, dst_max, src) safe_strncat(dst, dst_max, src, safe_strlen(src)+1)
+#define safe_strcmp(str1, str2) strcmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2))
+#define safe_strncmp(str1, str2, count) strncmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2), count)
+#define safe_strlen(str) ((str==NULL)?0:strlen(str))
+#define safe_sprintf _snprintf
+#define safe_unref_device(dev) do {if (dev != NULL) {libusb_unref_device(dev); dev = NULL;}} while(0)
+#define wchar_to_utf8_ms(wstr, str, strlen) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, strlen, NULL, NULL)
+inline void upperize(char* str) {
+ size_t i;
+ if (str == NULL) return;
+ for (i=0; i<safe_strlen(str); i++)
+ str[i] = (char)toupper((int)str[i]);
+}
+
+#define MAX_CTRL_BUFFER_LENGTH 4096
+#define MAX_USB_DEVICES 256
+#define MAX_USB_STRING_LENGTH 128
+#define MAX_HID_REPORT_SIZE 1024
+#define MAX_HID_DESCRIPTOR_SIZE 256
+#define MAX_GUID_STRING_LENGTH 40
+#define MAX_PATH_LENGTH 128
+#define MAX_KEY_LENGTH 256
+#define MAX_TIMER_SEMAPHORES 128
+#define TIMER_REQUEST_RETRY_MS 100
+#define ERR_BUFFER_SIZE 256
+#define LIST_SEPARATOR ';'
+#define HTAB_SIZE 1021
+
+// Handle code for HID interface that have been claimed ("dibs")
+#define INTERFACE_CLAIMED ((HANDLE)(intptr_t)0xD1B5)
+// Additional return code for HID operations that completed synchronously
+#define LIBUSB_COMPLETED (LIBUSB_SUCCESS + 1)
+
+// http://msdn.microsoft.com/en-us/library/ff545978.aspx
+// http://msdn.microsoft.com/en-us/library/ff545972.aspx
+// http://msdn.microsoft.com/en-us/library/ff545982.aspx
+#if !defined(GUID_DEVINTERFACE_USB_HOST_CONTROLLER)
+const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27} };
+#endif
+#if !defined(GUID_DEVINTERFACE_USB_DEVICE)
+const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED} };
+#endif
+#if !defined(GUID_DEVINTERFACE_USB_HUB)
+const GUID GUID_DEVINTERFACE_USB_HUB = { 0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8} };
+#endif
+const GUID GUID_NULL = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} };
+
+
+/*
+ * Multiple USB API backend support
+ */
+#define USB_API_UNSUPPORTED 0
+#define USB_API_HUB 1
+#define USB_API_COMPOSITE 2
+#define USB_API_WINUSB 3
+#define USB_API_HID 4
+#define USB_API_MAX 5
+
+#define CLASS_GUID_UNSUPPORTED GUID_NULL
+const GUID CLASS_GUID_HID = { 0x745A17A0, 0x74D3, 0x11D0, {0xB6, 0xFE, 0x00, 0xA0, 0xC9, 0x0F, 0x57, 0xDA} };
+const GUID CLASS_GUID_LIBUSB_WINUSB = { 0x78A1C341, 0x4539, 0x11D3, {0xB8, 0x8D, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71} };
+const GUID CLASS_GUID_COMPOSITE = { 0x36FC9E60, 0xC465, 0x11cF, {0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} };
+
+struct windows_usb_api_backend {
+ const uint8_t id;
+ const char* designation;
+ const GUID *class_guid; // The Class GUID (for fallback in case the driver name cannot be read)
+ const char **driver_name_list; // Driver name, without .sys, e.g. "usbccgp"
+ const uint8_t nb_driver_names;
+ int (*init)(struct libusb_context *ctx);
+ int (*exit)(void);
+ int (*open)(struct libusb_device_handle *dev_handle);
+ void (*close)(struct libusb_device_handle *dev_handle);
+ int (*claim_interface)(struct libusb_device_handle *dev_handle, int iface);
+ int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle, int iface, int altsetting);
+ int (*release_interface)(struct libusb_device_handle *dev_handle, int iface);
+ int (*clear_halt)(struct libusb_device_handle *dev_handle, unsigned char endpoint);
+ int (*reset_device)(struct libusb_device_handle *dev_handle);
+ int (*submit_bulk_transfer)(struct usbi_transfer *itransfer);
+ int (*submit_iso_transfer)(struct usbi_transfer *itransfer);
+ int (*submit_control_transfer)(struct usbi_transfer *itransfer);
+ int (*abort_control)(struct usbi_transfer *itransfer);
+ int (*abort_transfers)(struct usbi_transfer *itransfer);
+ int (*copy_transfer_data)(struct usbi_transfer *itransfer, uint32_t io_size);
+};
+
+extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX];
+
+#define PRINT_UNSUPPORTED_API(fname) \
+ usbi_dbg("unsupported API call for '" \
+ #fname "' (unrecognized device driver)"); \
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+
+/*
+ * private structures definition
+ * with inline pseudo constructors/destructors
+ */
+
+// TODO (v2+): move hid desc to libusb.h?
+struct libusb_hid_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdHID;
+ uint8_t bCountryCode;
+ uint8_t bNumDescriptors;
+ uint8_t bClassDescriptorType;
+ uint16_t wClassDescriptorLength;
+};
+#define LIBUSB_DT_HID_SIZE 9
+#define HID_MAX_CONFIG_DESC_SIZE (LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE \
+ + LIBUSB_DT_HID_SIZE + 2 * LIBUSB_DT_ENDPOINT_SIZE)
+#define HID_MAX_REPORT_SIZE 1024
+#define HID_IN_EP 0x81
+#define HID_OUT_EP 0x02
+#define LIBUSB_REQ_RECIPIENT(request_type) ((request_type) & 0x1F)
+#define LIBUSB_REQ_TYPE(request_type) ((request_type) & (0x03 << 5))
+#define LIBUSB_REQ_IN(request_type) ((request_type) & LIBUSB_ENDPOINT_IN)
+#define LIBUSB_REQ_OUT(request_type) (!LIBUSB_REQ_IN(request_type))
+
+// The following are used for HID reports IOCTLs
+#define HID_CTL_CODE(id) \
+ CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_NEITHER, FILE_ANY_ACCESS)
+#define HID_BUFFER_CTL_CODE(id) \
+ CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HID_IN_CTL_CODE(id) \
+ CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+#define HID_OUT_CTL_CODE(id) \
+ CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+
+#define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100)
+#define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104)
+#define IOCTL_HID_SET_FEATURE HID_IN_CTL_CODE(100)
+#define IOCTL_HID_SET_OUTPUT_REPORT HID_IN_CTL_CODE(101)
+
+enum libusb_hid_request_type {
+ HID_REQ_GET_REPORT = 0x01,
+ HID_REQ_GET_IDLE = 0x02,
+ HID_REQ_GET_PROTOCOL = 0x03,
+ HID_REQ_SET_REPORT = 0x09,
+ HID_REQ_SET_IDLE = 0x0A,
+ HID_REQ_SET_PROTOCOL = 0x0B
+};
+
+enum libusb_hid_report_type {
+ HID_REPORT_TYPE_INPUT = 0x01,
+ HID_REPORT_TYPE_OUTPUT = 0x02,
+ HID_REPORT_TYPE_FEATURE = 0x03
+};
+
+struct hid_device_priv {
+ uint16_t vid;
+ uint16_t pid;
+ uint8_t config;
+ uint8_t nb_interfaces;
+ bool uses_report_ids[3]; // input, ouptput, feature
+ uint16_t input_report_size;
+ uint16_t output_report_size;
+ uint16_t feature_report_size;
+ WCHAR string[3][MAX_USB_STRING_LENGTH];
+ uint8_t string_index[3]; // man, prod, ser
+};
+
+typedef struct libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
+struct windows_device_priv {
+ uint8_t depth; // distance to HCD
+ uint8_t port; // port number on the hub
+ struct libusb_device *parent_dev; // access to parent is required for usermode ops
+ char *path; // device interface path
+ struct windows_usb_api_backend const *apib;
+ struct {
+ char *path; // each interface needs a device interface path,
+ struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support),
+ int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
+ uint8_t *endpoint;
+ bool restricted_functionality; // indicates if the interface functionality is restricted
+ // by Windows (eg. HID keyboards or mice cannot do R/W)
+ } usb_interface[USB_MAXINTERFACES];
+ uint8_t composite_api_flags; // HID and composite devices require additional data
+ struct hid_device_priv *hid;
+ uint8_t active_config;
+ USB_DEVICE_DESCRIPTOR dev_descriptor;
+ unsigned char **config_descriptor; // list of pointers to the cached config descriptors
+};
+
+static inline struct windows_device_priv *__device_priv(struct libusb_device *dev) {
+ return (struct windows_device_priv *)dev->os_priv;
+}
+
+static inline void windows_device_priv_init(libusb_device* dev) {
+ struct windows_device_priv* p = __device_priv(dev);
+ int i;
+ p->depth = 0;
+ p->port = 0;
+ p->parent_dev = NULL;
+ p->path = NULL;
+ p->apib = &usb_api_backend[USB_API_UNSUPPORTED];
+ p->composite_api_flags = 0;
+ p->hid = NULL;
+ p->active_config = 0;
+ p->config_descriptor = NULL;
+ memset(&(p->dev_descriptor), 0, sizeof(USB_DEVICE_DESCRIPTOR));
+ for (i=0; i<USB_MAXINTERFACES; i++) {
+ p->usb_interface[i].path = NULL;
+ p->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED];
+ p->usb_interface[i].nb_endpoints = 0;
+ p->usb_interface[i].endpoint = NULL;
+ p->usb_interface[i].restricted_functionality = false;
+ }
+}
+
+static inline void windows_device_priv_release(libusb_device* dev) {
+ struct windows_device_priv* p = __device_priv(dev);
+ int i;
+ safe_free(p->path);
+ if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) {
+ for (i=0; i < dev->num_configurations; i++)
+ safe_free(p->config_descriptor[i]);
+ }
+ safe_free(p->config_descriptor);
+ safe_free(p->hid);
+ for (i=0; i<USB_MAXINTERFACES; i++) {
+ safe_free(p->usb_interface[i].path);
+ safe_free(p->usb_interface[i].endpoint);
+ }
+}
+
+struct interface_handle_t {
+ HANDLE dev_handle; // WinUSB needs an extra handle for the file
+ HANDLE api_handle; // used by the API to communicate with the device
+};
+
+struct windows_device_handle_priv {
+ int active_interface;
+ struct interface_handle_t interface_handle[USB_MAXINTERFACES];
+#if defined(AUTO_CLAIM)
+ int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
+#endif
+};
+
+static inline struct windows_device_handle_priv *__device_handle_priv(
+ struct libusb_device_handle *handle)
+{
+ return (struct windows_device_handle_priv *) handle->os_priv;
+}
+
+// used for async polling functions
+struct windows_transfer_priv {
+ struct winfd pollable_fd;
+ uint8_t interface_number;
+ uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID
+ uint8_t *hid_dest; // transfer buffer destination, required for HID
+ size_t hid_expected_size;
+};
+
+// used to match a device driver (including filter drivers) against a supported API
+struct driver_lookup {
+ char list[MAX_KEY_LENGTH+1];// REG_MULTI_SZ list of services (driver) names
+ const DWORD reg_prop; // SPDRP registry key to use to retreive list
+ const char* designation; // internal designation (for debug output)
+};
+
+/*
+ * API macros - from libusb-win32 1.x
+ */
+#define DLL_DECLARE_PREFIXED(api, ret, prefix, name, args) \
+ typedef ret (api * __dll_##name##_t)args; \
+ static __dll_##name##_t prefix##name = NULL
+
+#define DLL_LOAD_PREFIXED(dll, prefix, name, ret_on_failure) \
+ do { \
+ HMODULE h = GetModuleHandleA(#dll); \
+ if (!h) \
+ h = LoadLibraryA(#dll); \
+ if (!h) { \
+ if (ret_on_failure) { return LIBUSB_ERROR_NOT_FOUND; }\
+ else { break; } \
+ } \
+ prefix##name = (__dll_##name##_t)GetProcAddress(h, #name);\
+ if (prefix##name) break; \
+ prefix##name = (__dll_##name##_t)GetProcAddress(h, #name "A");\
+ if (prefix##name) break; \
+ prefix##name = (__dll_##name##_t)GetProcAddress(h, #name "W");\
+ if (prefix##name) break; \
+ if(ret_on_failure) \
+ return LIBUSB_ERROR_NOT_FOUND; \
+ } while(0)
+
+#define DLL_DECLARE(api, ret, name, args) DLL_DECLARE_PREFIXED(api, ret, , name, args)
+#define DLL_LOAD(dll, name, ret_on_failure) DLL_LOAD_PREFIXED(dll, , name, ret_on_failure)
+
+/* OLE32 dependency */
+DLL_DECLARE_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID));
+
+/* SetupAPI dependencies */
+DLL_DECLARE_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (const GUID*, PCSTR, HWND, DWORD));
+DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA));
+DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA,
+ const GUID*, DWORD, PSP_DEVICE_INTERFACE_DATA));
+DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA,
+ PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA));
+DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO));
+DLL_DECLARE_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM));
+DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO,
+ PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD));
+DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
+DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY));
+
+/*
+ * Windows DDK API definitions. Most of it copied from MinGW's includes
+ */
+typedef DWORD DEVNODE, DEVINST;
+typedef DEVNODE *PDEVNODE, *PDEVINST;
+typedef DWORD RETURN_TYPE;
+typedef RETURN_TYPE CONFIGRET;
+
+#define CR_SUCCESS 0x00000000
+#define CR_NO_SUCH_DEVNODE 0x0000000D
+
+#define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE
+#define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG
+#define USB_STRING_DESCRIPTOR_TYPE LIBUSB_DT_STRING
+#define USB_INTERFACE_DESCRIPTOR_TYPE LIBUSB_DT_INTERFACE
+#define USB_ENDPOINT_DESCRIPTOR_TYPE LIBUSB_DT_ENDPOINT
+
+#define USB_REQUEST_GET_STATUS LIBUSB_REQUEST_GET_STATUS
+#define USB_REQUEST_CLEAR_FEATURE LIBUSB_REQUEST_CLEAR_FEATURE
+#define USB_REQUEST_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE
+#define USB_REQUEST_SET_ADDRESS LIBUSB_REQUEST_SET_ADDRESS
+#define USB_REQUEST_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR
+#define USB_REQUEST_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR
+#define USB_REQUEST_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION
+#define USB_REQUEST_SET_CONFIGURATION LIBUSB_REQUEST_SET_CONFIGURATION
+#define USB_REQUEST_GET_INTERFACE LIBUSB_REQUEST_GET_INTERFACE
+#define USB_REQUEST_SET_INTERFACE LIBUSB_REQUEST_SET_INTERFACE
+#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME
+
+#define USB_GET_NODE_INFORMATION 258
+#define USB_GET_NODE_CONNECTION_INFORMATION 259
+#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260
+#define USB_GET_NODE_CONNECTION_NAME 261
+#define USB_GET_HUB_CAPABILITIES 271
+#if !defined(USB_GET_HUB_CAPABILITIES_EX)
+#define USB_GET_HUB_CAPABILITIES_EX 276
+#endif
+
+#ifndef METHOD_BUFFERED
+#define METHOD_BUFFERED 0
+#endif
+#ifndef FILE_ANY_ACCESS
+#define FILE_ANY_ACCESS 0x00000000
+#endif
+#ifndef FILE_DEVICE_UNKNOWN
+#define FILE_DEVICE_UNKNOWN 0x00000022
+#endif
+#ifndef FILE_DEVICE_USB
+#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN
+#endif
+
+#ifndef CTL_CODE
+#define CTL_CODE(DeviceType, Function, Method, Access)( \
+ ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
+#endif
+
+typedef enum _USB_CONNECTION_STATUS {
+ NoDeviceConnected,
+ DeviceConnected,
+ DeviceFailedEnumeration,
+ DeviceGeneralFailure,
+ DeviceCausedOvercurrent,
+ DeviceNotEnoughPower,
+ DeviceNotEnoughBandwidth,
+ DeviceHubNestedTooDeeply,
+ DeviceInLegacyHub
+} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS;
+
+typedef enum _USB_HUB_NODE {
+ UsbHub,
+ UsbMIParent
+} USB_HUB_NODE;
+
+/* Cfgmgr32.dll interface */
+DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG));
+DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG));
+DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG));
+DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG));
+
+#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \
+ CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_USB_GET_HUB_CAPABILITIES \
+ CTL_CODE(FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \
+ CTL_CODE(FILE_DEVICE_USB, USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_USB_GET_ROOT_HUB_NAME \
+ CTL_CODE(FILE_DEVICE_USB, HCD_GET_ROOT_HUB_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_USB_GET_NODE_INFORMATION \
+ CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION \
+ CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES \
+ CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_ATTRIBUTES, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_USB_GET_NODE_CONNECTION_NAME \
+ CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+// Most of the structures below need to be packed
+#pragma pack(push, 1)
+
+typedef struct _USB_INTERFACE_DESCRIPTOR {
+ UCHAR bLength;
+ UCHAR bDescriptorType;
+ UCHAR bInterfaceNumber;
+ UCHAR bAlternateSetting;
+ UCHAR bNumEndpoints;
+ UCHAR bInterfaceClass;
+ UCHAR bInterfaceSubClass;
+ UCHAR bInterfaceProtocol;
+ UCHAR iInterface;
+} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR;
+
+typedef struct _USB_CONFIGURATION_DESCRIPTOR {
+ UCHAR bLength;
+ UCHAR bDescriptorType;
+ USHORT wTotalLength;
+ UCHAR bNumInterfaces;
+ UCHAR bConfigurationValue;
+ UCHAR iConfiguration;
+ UCHAR bmAttributes;
+ UCHAR MaxPower;
+} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
+
+typedef struct _USB_CONFIGURATION_DESCRIPTOR_SHORT {
+ struct {
+ ULONG ConnectionIndex;
+ struct {
+ UCHAR bmRequest;
+ UCHAR bRequest;
+ USHORT wValue;
+ USHORT wIndex;
+ USHORT wLength;
+ } SetupPacket;
+ } req;
+ USB_CONFIGURATION_DESCRIPTOR data;
+} USB_CONFIGURATION_DESCRIPTOR_SHORT;
+
+typedef struct _USB_ENDPOINT_DESCRIPTOR {
+ UCHAR bLength;
+ UCHAR bDescriptorType;
+ UCHAR bEndpointAddress;
+ UCHAR bmAttributes;
+ USHORT wMaxPacketSize;
+ UCHAR bInterval;
+} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR;
+
+typedef struct _USB_DESCRIPTOR_REQUEST {
+ ULONG ConnectionIndex;
+ struct {
+ UCHAR bmRequest;
+ UCHAR bRequest;
+ USHORT wValue;
+ USHORT wIndex;
+ USHORT wLength;
+ } SetupPacket;
+// UCHAR Data[0];
+} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST;
+
+typedef struct _USB_HUB_DESCRIPTOR {
+ UCHAR bDescriptorLength;
+ UCHAR bDescriptorType;
+ UCHAR bNumberOfPorts;
+ USHORT wHubCharacteristics;
+ UCHAR bPowerOnToPowerGood;
+ UCHAR bHubControlCurrent;
+ UCHAR bRemoveAndPowerMask[64];
+} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR;
+
+typedef struct _USB_ROOT_HUB_NAME {
+ ULONG ActualLength;
+ WCHAR RootHubName[1];
+} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME;
+
+typedef struct _USB_ROOT_HUB_NAME_FIXED {
+ ULONG ActualLength;
+ WCHAR RootHubName[MAX_PATH_LENGTH];
+} USB_ROOT_HUB_NAME_FIXED;
+
+typedef struct _USB_NODE_CONNECTION_NAME {
+ ULONG ConnectionIndex;
+ ULONG ActualLength;
+ WCHAR NodeName[1];
+} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME;
+
+typedef struct _USB_NODE_CONNECTION_NAME_FIXED {
+ ULONG ConnectionIndex;
+ ULONG ActualLength;
+ WCHAR NodeName[MAX_PATH_LENGTH];
+} USB_NODE_CONNECTION_NAME_FIXED;
+
+typedef struct _USB_HUB_NAME_FIXED {
+ union {
+ USB_ROOT_HUB_NAME_FIXED root;
+ USB_NODE_CONNECTION_NAME_FIXED node;
+ } u;
+} USB_HUB_NAME_FIXED;
+
+
+typedef struct _USB_HUB_INFORMATION {
+ USB_HUB_DESCRIPTOR HubDescriptor;
+ BOOLEAN HubIsBusPowered;
+} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION;
+
+typedef struct _USB_MI_PARENT_INFORMATION {
+ ULONG NumberOfInterfaces;
+} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION;
+
+typedef struct _USB_NODE_INFORMATION {
+ USB_HUB_NODE NodeType;
+ union {
+ USB_HUB_INFORMATION HubInformation;
+ USB_MI_PARENT_INFORMATION MiParentInformation;
+ } u;
+} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION;
+
+typedef struct _USB_PIPE_INFO {
+ USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+ ULONG ScheduleOffset;
+} USB_PIPE_INFO, *PUSB_PIPE_INFO;
+
+typedef struct _USB_NODE_CONNECTION_INFORMATION {
+ ULONG ConnectionIndex;
+ USB_DEVICE_DESCRIPTOR DeviceDescriptor;
+ UCHAR CurrentConfigurationValue;
+ BOOLEAN LowSpeed;
+ BOOLEAN DeviceIsHub;
+ USHORT DeviceAddress;
+ ULONG NumberOfOpenPipes;
+ USB_CONNECTION_STATUS ConnectionStatus;
+// USB_PIPE_INFO PipeList[0];
+} USB_NODE_CONNECTION_INFORMATION, *PUSB_NODE_CONNECTION_INFORMATION;
+
+typedef struct _USB_HUB_CAP_FLAGS {
+ ULONG HubIsHighSpeedCapable:1;
+ ULONG HubIsHighSpeed:1;
+ ULONG HubIsMultiTtCapable:1;
+ ULONG HubIsMultiTt:1;
+ ULONG HubIsRoot:1;
+ ULONG HubIsArmedWakeOnConnect:1;
+ ULONG ReservedMBZ:26;
+} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS;
+
+typedef struct _USB_HUB_CAPABILITIES {
+ ULONG HubIs2xCapable : 1;
+} USB_HUB_CAPABILITIES, *PUSB_HUB_CAPABILITIES;
+
+typedef struct _USB_HUB_CAPABILITIES_EX {
+ USB_HUB_CAP_FLAGS CapabilityFlags;
+} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX;
+
+#pragma pack(pop)
+
+/* winusb.dll interface */
+
+#define SHORT_PACKET_TERMINATE 0x01
+#define AUTO_CLEAR_STALL 0x02
+#define PIPE_TRANSFER_TIMEOUT 0x03
+#define IGNORE_SHORT_PACKETS 0x04
+#define ALLOW_PARTIAL_READS 0x05
+#define AUTO_FLUSH 0x06
+#define RAW_IO 0x07
+#define MAXIMUM_TRANSFER_SIZE 0x08
+#define AUTO_SUSPEND 0x81
+#define SUSPEND_DELAY 0x83
+#define DEVICE_SPEED 0x01
+#define LowSpeed 0x01
+#define FullSpeed 0x02
+#define HighSpeed 0x03
+
+typedef enum _USBD_PIPE_TYPE {
+ UsbdPipeTypeControl,
+ UsbdPipeTypeIsochronous,
+ UsbdPipeTypeBulk,
+ UsbdPipeTypeInterrupt
+} USBD_PIPE_TYPE;
+
+typedef struct {
+ USBD_PIPE_TYPE PipeType;
+ UCHAR PipeId;
+ USHORT MaximumPacketSize;
+ UCHAR Interval;
+} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION;
+
+#pragma pack(1)
+typedef struct {
+ UCHAR request_type;
+ UCHAR request;
+ USHORT value;
+ USHORT index;
+ USHORT length;
+} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET;
+#pragma pack()
+
+typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
+
+DLL_DECLARE(WINAPI, BOOL, WinUsb_Initialize, (HANDLE, PWINUSB_INTERFACE_HANDLE));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_Free, (WINUSB_INTERFACE_HANDLE));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetAssociatedInterface, (WINUSB_INTERFACE_HANDLE, UCHAR, PWINUSB_INTERFACE_HANDLE));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetDescriptor, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, USHORT, PUCHAR, ULONG, PULONG));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryInterfaceSettings, (WINUSB_INTERFACE_HANDLE, UCHAR, PUSB_INTERFACE_DESCRIPTOR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryDeviceInformation, (WINUSB_INTERFACE_HANDLE, ULONG, PULONG, PVOID));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_SetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, PUCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, PWINUSB_PIPE_INFORMATION));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_SetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, ULONG, PVOID));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, PULONG, PVOID));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_ReadPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_WritePipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_ControlTransfer, (WINUSB_INTERFACE_HANDLE, WINUSB_SETUP_PACKET, PUCHAR, ULONG, PULONG, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_ResetPipe, (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_AbortPipe, (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_FlushPipe, (WINUSB_INTERFACE_HANDLE, UCHAR));
+
+/* hid.dll interface */
+
+#define HIDP_STATUS_SUCCESS 0x110000
+typedef void* PHIDP_PREPARSED_DATA;
+
+#pragma pack(1)
+typedef struct {
+ ULONG Size;
+ USHORT VendorID;
+ USHORT ProductID;
+ USHORT VersionNumber;
+} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
+#pragma pack()
+
+typedef USHORT USAGE;
+typedef struct {
+ USAGE Usage;
+ USAGE UsagePage;
+ USHORT InputReportByteLength;
+ USHORT OutputReportByteLength;
+ USHORT FeatureReportByteLength;
+ USHORT Reserved[17];
+ USHORT NumberLinkCollectionNodes;
+ USHORT NumberInputButtonCaps;
+ USHORT NumberInputValueCaps;
+ USHORT NumberInputDataIndices;
+ USHORT NumberOutputButtonCaps;
+ USHORT NumberOutputValueCaps;
+ USHORT NumberOutputDataIndices;
+ USHORT NumberFeatureButtonCaps;
+ USHORT NumberFeatureValueCaps;
+ USHORT NumberFeatureDataIndices;
+} HIDP_CAPS, *PHIDP_CAPS;
+
+typedef enum _HIDP_REPORT_TYPE {
+ HidP_Input,
+ HidP_Output,
+ HidP_Feature
+} HIDP_REPORT_TYPE;
+
+typedef struct _HIDP_VALUE_CAPS {
+ USAGE UsagePage;
+ UCHAR ReportID;
+ BOOLEAN IsAlias;
+ USHORT BitField;
+ USHORT LinkCollection;
+ USAGE LinkUsage;
+ USAGE LinkUsagePage;
+ BOOLEAN IsRange;
+ BOOLEAN IsStringRange;
+ BOOLEAN IsDesignatorRange;
+ BOOLEAN IsAbsolute;
+ BOOLEAN HasNull;
+ UCHAR Reserved;
+ USHORT BitSize;
+ USHORT ReportCount;
+ USHORT Reserved2[5];
+ ULONG UnitsExp;
+ ULONG Units;
+ LONG LogicalMin, LogicalMax;
+ LONG PhysicalMin, PhysicalMax;
+ union {
+ struct {
+ USAGE UsageMin, UsageMax;
+ USHORT StringMin, StringMax;
+ USHORT DesignatorMin, DesignatorMax;
+ USHORT DataIndexMin, DataIndexMax;
+ } Range;
+ struct {
+ USAGE Usage, Reserved1;
+ USHORT StringIndex, Reserved2;
+ USHORT DesignatorIndex, Reserved3;
+ USHORT DataIndex, Reserved4;
+ } NotRange;
+ } u;
+} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS;
+
+DLL_DECLARE(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES));
+DLL_DECLARE(WINAPI, VOID, HidD_GetHidGuid, (LPGUID));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetPreparsedData, (HANDLE, PHIDP_PREPARSED_DATA *));
+DLL_DECLARE(WINAPI, BOOL, HidD_FreePreparsedData, (PHIDP_PREPARSED_DATA));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetManufacturerString, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetProductString, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetSerialNumberString, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, LONG, HidP_GetCaps, (PHIDP_PREPARSED_DATA, PHIDP_CAPS));
+DLL_DECLARE(WINAPI, BOOL, HidD_SetNumInputBuffers, (HANDLE, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_SetFeature, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetFeature, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetInputReport, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_SetOutputReport, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_FlushQueue, (HANDLE));
+DLL_DECLARE(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA));
diff --git a/libusb-1.0/libusb/sync.c b/libusb-1.0/libusb/sync.c
new file mode 100644
index 0000000..d040d98
--- /dev/null
+++ b/libusb-1.0/libusb/sync.c
@@ -0,0 +1,310 @@
+/*
+ * Synchronous I/O functions for libusb
+ * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libusbi.h"
+
+/**
+ * @defgroup syncio Synchronous device I/O
+ *
+ * This page documents libusb's synchronous (blocking) API for USB device I/O.
+ * This interface is easy to use but has some limitations. More advanced users
+ * may wish to consider using the \ref asyncio "asynchronous I/O API" instead.
+ */
+
+static void LIBUSB_CALL ctrl_transfer_cb(struct libusb_transfer *transfer)
+{
+ int *completed = transfer->user_data;
+ *completed = 1;
+ usbi_dbg("actual_length=%d", transfer->actual_length);
+ /* caller interprets result and frees transfer */
+}
+
+/** \ingroup syncio
+ * Perform a USB control transfer.
+ *
+ * The direction of the transfer is inferred from the bmRequestType field of
+ * the setup packet.
+ *
+ * The wValue, wIndex and wLength fields values should be given in host-endian
+ * byte order.
+ *
+ * \param dev_handle a handle for the device to communicate with
+ * \param bmRequestType the request type field for the setup packet
+ * \param bRequest the request field for the setup packet
+ * \param wValue the value field for the setup packet
+ * \param wIndex the index field for the setup packet
+ * \param data a suitably-sized data buffer for either input or output
+ * (depending on direction bits within bmRequestType)
+ * \param wLength the length field for the setup packet. The data buffer should
+ * be at least this size.
+ * \param timeout timeout (in millseconds) that this function should wait
+ * before giving up due to no response being received. For an unlimited
+ * timeout, use value 0.
+ * \returns on success, the number of bytes actually transferred
+ * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out
+ * \returns LIBUSB_ERROR_PIPE if the control request was not supported by the
+ * device
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failures
+ */
+int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle,
+ uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
+ unsigned char *data, uint16_t wLength, unsigned int timeout)
+{
+ struct libusb_transfer *transfer = libusb_alloc_transfer(0);
+ unsigned char *buffer;
+ int completed = 0;
+ int r;
+
+ if (!transfer)
+ return LIBUSB_ERROR_NO_MEM;
+
+ buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE + wLength);
+ if (!buffer) {
+ libusb_free_transfer(transfer);
+ return LIBUSB_ERROR_NO_MEM;
+ }
+
+ libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex,
+ wLength);
+ if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT)
+ memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength);
+
+ libusb_fill_control_transfer(transfer, dev_handle, buffer,
+ ctrl_transfer_cb, &completed, timeout);
+ transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER;
+ r = libusb_submit_transfer(transfer);
+ if (r < 0) {
+ libusb_free_transfer(transfer);
+ return r;
+ }
+
+ while (!completed) {
+ r = libusb_handle_events_check(HANDLE_CTX(dev_handle), &completed);
+ if (r < 0) {
+ if (r == LIBUSB_ERROR_INTERRUPTED)
+ continue;
+ libusb_cancel_transfer(transfer);
+ while (!completed)
+ if (libusb_handle_events_check(HANDLE_CTX(dev_handle), &completed) < 0)
+ break;
+ libusb_free_transfer(transfer);
+ return r;
+ }
+ }
+
+ if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
+ memcpy(data, libusb_control_transfer_get_data(transfer),
+ transfer->actual_length);
+
+ switch (transfer->status) {
+ case LIBUSB_TRANSFER_COMPLETED:
+ r = transfer->actual_length;
+ break;
+ case LIBUSB_TRANSFER_TIMED_OUT:
+ r = LIBUSB_ERROR_TIMEOUT;
+ break;
+ case LIBUSB_TRANSFER_STALL:
+ r = LIBUSB_ERROR_PIPE;
+ break;
+ case LIBUSB_TRANSFER_NO_DEVICE:
+ r = LIBUSB_ERROR_NO_DEVICE;
+ break;
+ default:
+ usbi_warn(HANDLE_CTX(dev_handle),
+ "unrecognised status code %d", transfer->status);
+ r = LIBUSB_ERROR_OTHER;
+ }
+
+ libusb_free_transfer(transfer);
+ return r;
+}
+
+static void LIBUSB_CALL bulk_transfer_cb(struct libusb_transfer *transfer)
+{
+ int *completed = transfer->user_data;
+ *completed = 1;
+ usbi_dbg("actual_length=%d", transfer->actual_length);
+ /* caller interprets results and frees transfer */
+}
+
+static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
+ unsigned char endpoint, unsigned char *buffer, int length,
+ int *transferred, unsigned int timeout, unsigned char type)
+{
+ struct libusb_transfer *transfer = libusb_alloc_transfer(0);
+ int completed = 0;
+ int r;
+
+ if (!transfer)
+ return LIBUSB_ERROR_NO_MEM;
+
+ libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
+ bulk_transfer_cb, &completed, timeout);
+ transfer->type = type;
+
+ r = libusb_submit_transfer(transfer);
+ if (r < 0) {
+ libusb_free_transfer(transfer);
+ return r;
+ }
+
+ while (!completed) {
+ r = libusb_handle_events_check(HANDLE_CTX(dev_handle), &completed);
+ if (r < 0) {
+ if (r == LIBUSB_ERROR_INTERRUPTED)
+ continue;
+ libusb_cancel_transfer(transfer);
+ while (!completed)
+ if (libusb_handle_events_check(HANDLE_CTX(dev_handle), &completed) < 0)
+ break;
+ libusb_free_transfer(transfer);
+ return r;
+ }
+ }
+
+ *transferred = transfer->actual_length;
+ switch (transfer->status) {
+ case LIBUSB_TRANSFER_COMPLETED:
+ r = 0;
+ break;
+ case LIBUSB_TRANSFER_TIMED_OUT:
+ r = LIBUSB_ERROR_TIMEOUT;
+ break;
+ case LIBUSB_TRANSFER_STALL:
+ r = LIBUSB_ERROR_PIPE;
+ break;
+ case LIBUSB_TRANSFER_OVERFLOW:
+ r = LIBUSB_ERROR_OVERFLOW;
+ break;
+ case LIBUSB_TRANSFER_NO_DEVICE:
+ r = LIBUSB_ERROR_NO_DEVICE;
+ break;
+ default:
+ usbi_warn(HANDLE_CTX(dev_handle),
+ "unrecognised status code %d", transfer->status);
+ r = LIBUSB_ERROR_OTHER;
+ }
+
+ libusb_free_transfer(transfer);
+ return r;
+}
+
+/** \ingroup syncio
+ * Perform a USB bulk transfer. The direction of the transfer is inferred from
+ * the direction bits of the endpoint address.
+ *
+ * For bulk reads, the <tt>length</tt> field indicates the maximum length of
+ * data you are expecting to receive. If less data arrives than expected,
+ * this function will return that data, so be sure to check the
+ * <tt>transferred</tt> output parameter.
+ *
+ * You should also check the <tt>transferred</tt> parameter for bulk writes.
+ * Not all of the data may have been written.
+ *
+ * Also check <tt>transferred</tt> when dealing with a timeout error code.
+ * libusb may have to split your transfer into a number of chunks to satisfy
+ * underlying O/S requirements, meaning that the timeout may expire after
+ * the first few chunks have completed. libusb is careful not to lose any data
+ * that may have been transferred; do not assume that timeout conditions
+ * indicate a complete lack of I/O.
+ *
+ * \param dev_handle a handle for the device to communicate with
+ * \param endpoint the address of a valid endpoint to communicate with
+ * \param data a suitably-sized data buffer for either input or output
+ * (depending on endpoint)
+ * \param length for bulk writes, the number of bytes from data to be sent. for
+ * bulk reads, the maximum number of bytes to receive into the data buffer.
+ * \param transferred output location for the number of bytes actually
+ * transferred.
+ * \param timeout timeout (in millseconds) that this function should wait
+ * before giving up due to no response being received. For an unlimited
+ * timeout, use value 0.
+ *
+ * \returns 0 on success (and populates <tt>transferred</tt>)
+ * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates
+ * <tt>transferred</tt>)
+ * \returns LIBUSB_ERROR_PIPE if the endpoint halted
+ * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see
+ * \ref packetoverflow
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failures
+ */
+int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle,
+ unsigned char endpoint, unsigned char *data, int length, int *transferred,
+ unsigned int timeout)
+{
+ return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
+ transferred, timeout, LIBUSB_TRANSFER_TYPE_BULK);
+}
+
+/** \ingroup syncio
+ * Perform a USB interrupt transfer. The direction of the transfer is inferred
+ * from the direction bits of the endpoint address.
+ *
+ * For interrupt reads, the <tt>length</tt> field indicates the maximum length
+ * of data you are expecting to receive. If less data arrives than expected,
+ * this function will return that data, so be sure to check the
+ * <tt>transferred</tt> output parameter.
+ *
+ * You should also check the <tt>transferred</tt> parameter for interrupt
+ * writes. Not all of the data may have been written.
+ *
+ * Also check <tt>transferred</tt> when dealing with a timeout error code.
+ * libusb may have to split your transfer into a number of chunks to satisfy
+ * underlying O/S requirements, meaning that the timeout may expire after
+ * the first few chunks have completed. libusb is careful not to lose any data
+ * that may have been transferred; do not assume that timeout conditions
+ * indicate a complete lack of I/O.
+ *
+ * The default endpoint bInterval value is used as the polling interval.
+ *
+ * \param dev_handle a handle for the device to communicate with
+ * \param endpoint the address of a valid endpoint to communicate with
+ * \param data a suitably-sized data buffer for either input or output
+ * (depending on endpoint)
+ * \param length for bulk writes, the number of bytes from data to be sent. for
+ * bulk reads, the maximum number of bytes to receive into the data buffer.
+ * \param transferred output location for the number of bytes actually
+ * transferred.
+ * \param timeout timeout (in millseconds) that this function should wait
+ * before giving up due to no response being received. For an unlimited
+ * timeout, use value 0.
+ *
+ * \returns 0 on success (and populates <tt>transferred</tt>)
+ * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out
+ * \returns LIBUSB_ERROR_PIPE if the endpoint halted
+ * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see
+ * \ref packetoverflow
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns another LIBUSB_ERROR code on other error
+ */
+int API_EXPORTED libusb_interrupt_transfer(
+ struct libusb_device_handle *dev_handle, unsigned char endpoint,
+ unsigned char *data, int length, int *transferred, unsigned int timeout)
+{
+ return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
+ transferred, timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
+}