Browse Source

First import of libusb-1.0

ckolivas 12 years ago
parent
commit
6df0648a41
73 changed files with 41750 additions and 23 deletions
  1. 12 6
      Makefile.am
  2. 6 3
      compat/Makefile.am
  3. 46 0
      compat/libusb-1.0/AUTHORS
  4. 504 0
      compat/libusb-1.0/COPYING
  5. 5113 0
      compat/libusb-1.0/ChangeLog
  6. 28 0
      compat/libusb-1.0/Makefile.am
  7. 65 0
      compat/libusb-1.0/NEWS
  8. 95 0
      compat/libusb-1.0/PORTING
  9. 22 0
      compat/libusb-1.0/README
  10. 8 0
      compat/libusb-1.0/THANKS
  11. 9 0
      compat/libusb-1.0/TODO
  12. 232 0
      compat/libusb-1.0/configure.ac
  13. 10 0
      compat/libusb-1.0/doc/Makefile.am
  14. 1294 0
      compat/libusb-1.0/doc/doxygen.cfg.in
  15. 15 0
      compat/libusb-1.0/examples/Makefile.am
  16. 507 0
      compat/libusb-1.0/examples/dpfp.c
  17. 545 0
      compat/libusb-1.0/examples/dpfp_threaded.c
  18. 95 0
      compat/libusb-1.0/examples/hotplugtest.c
  19. 64 0
      compat/libusb-1.0/examples/listdevs.c
  20. 193 0
      compat/libusb-1.0/examples/sam3u_benchmark.c
  21. 256 0
      compat/libusb-1.0/examples/testlibusb1.c
  22. 12 0
      compat/libusb-1.0/libusb-1.0.pc.in
  23. 55 0
      compat/libusb-1.0/libusb/Makefile.am
  24. 2049 0
      compat/libusb-1.0/libusb/core.c
  25. 871 0
      compat/libusb-1.0/libusb/descriptor.c
  26. 298 0
      compat/libusb-1.0/libusb/hotplug.c
  27. 77 0
      compat/libusb-1.0/libusb/hotplug.h
  28. 2500 0
      compat/libusb-1.0/libusb/io.c
  29. 120 0
      compat/libusb-1.0/libusb/libusb-1.0.def
  30. 56 0
      compat/libusb-1.0/libusb/libusb-1.0.rc
  31. 1779 0
      compat/libusb-1.0/libusb/libusb.h
  32. 974 0
      compat/libusb-1.0/libusb/libusbi.h
  33. 1788 0
      compat/libusb-1.0/libusb/os/darwin_usb.c
  34. 175 0
      compat/libusb-1.0/libusb/os/darwin_usb.h
  35. 231 0
      compat/libusb-1.0/libusb/os/linux_netlink.c
  36. 242 0
      compat/libusb-1.0/libusb/os/linux_udev.c
  37. 2605 0
      compat/libusb-1.0/libusb/os/linux_usbfs.c
  38. 168 0
      compat/libusb-1.0/libusb/os/linux_usbfs.h
  39. 727 0
      compat/libusb-1.0/libusb/os/openbsd_usb.c
  40. 10 0
      compat/libusb-1.0/libusb/os/poll_posix.h
  41. 745 0
      compat/libusb-1.0/libusb/os/poll_windows.c
  42. 117 0
      compat/libusb-1.0/libusb/os/poll_windows.h
  43. 55 0
      compat/libusb-1.0/libusb/os/threads_posix.c
  44. 48 0
      compat/libusb-1.0/libusb/os/threads_posix.h
  45. 208 0
      compat/libusb-1.0/libusb/os/threads_windows.c
  46. 88 0
      compat/libusb-1.0/libusb/os/threads_windows.h
  47. 3000 0
      compat/libusb-1.0/libusb/os/windows_usb.c
  48. 608 0
      compat/libusb-1.0/libusb/os/windows_usb.h
  49. 322 0
      compat/libusb-1.0/libusb/sync.c
  50. 18 0
      compat/libusb-1.0/libusb/version.h
  51. 9661 0
      compat/libusb-1.0/ltmain.sh
  52. 106 0
      compat/libusb-1.0/msvc/ddk_build.cmd
  53. 142 0
      compat/libusb-1.0/msvc/ddk_build.cmd.orig
  54. 56 0
      compat/libusb-1.0/msvc/libusb.dsw
  55. 190 0
      compat/libusb-1.0/msvc/libusb_dll.dsp
  56. 421 0
      compat/libusb-1.0/msvc/libusb_dll.vcproj
  57. 166 0
      compat/libusb-1.0/msvc/libusb_dll.vcxproj
  58. 69 0
      compat/libusb-1.0/msvc/libusb_dll.vcxproj.filters
  59. 36 0
      compat/libusb-1.0/msvc/libusb_sources
  60. 170 0
      compat/libusb-1.0/msvc/libusb_static.dsp
  61. 346 0
      compat/libusb-1.0/msvc/libusb_static.vcproj
  62. 150 0
      compat/libusb-1.0/msvc/libusb_static.vcxproj
  63. 56 0
      compat/libusb-1.0/msvc/libusb_static.vcxproj.filters
  64. 61 0
      compat/libusb-1.0/msvc/libusb_vs2005.sln
  65. 49 0
      compat/libusb-1.0/msvc/libusb_vs2010.sln
  66. 77 0
      compat/libusb-1.0/msvc/libusb_vs2010.sln.orig
  67. 103 0
      compat/libusb-1.0/msvc/listdevs.dsp
  68. 360 0
      compat/libusb-1.0/msvc/listdevs.vcproj
  69. 165 0
      compat/libusb-1.0/msvc/listdevs.vcxproj
  70. 14 0
      compat/libusb-1.0/msvc/listdevs.vcxproj.filters
  71. 19 0
      compat/libusb-1.0/msvc/listdevs_sources
  72. 256 0
      compat/libusb-1.0/msvc/stdint.h
  73. 12 14
      configure.ac

+ 12 - 6
Makefile.am

@@ -7,6 +7,12 @@ else
 JANSSON_INCLUDES=
 endif
 
+if WANT_USBUTILS
+USBUTILS_INCLUDES = -I$(top_srcdir)/compat/libusb-1.0/libusb
+else
+USBUTILS_INCLUDES =
+endif
+
 EXTRA_DIST	= example.conf m4/gnulib-cache.m4 linux-usb-cgminer \
 		  ADL_SDK/readme.txt api-example.php miner.php	\
 		  API.class API.java api-example.c windows-build.txt \
@@ -16,7 +22,7 @@ EXTRA_DIST	= example.conf m4/gnulib-cache.m4 linux-usb-cgminer \
 
 SUBDIRS		= lib compat ccan
 
-INCLUDES	= $(PTHREAD_FLAGS) -fno-strict-aliasing $(JANSSON_INCLUDES)
+INCLUDES	= $(PTHREAD_FLAGS) -fno-strict-aliasing $(JANSSON_INCLUDES) $(USBUTILS_INCLUDES)
 
 bin_PROGRAMS	= cgminer
 
@@ -29,9 +35,9 @@ cgminer_LDADD	= $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
 		  @MATH_LIBS@ lib/libgnu.a ccan/libccan.a
 
 if HAVE_WINDOWS
-cgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @OPENCL_FLAGS@ @LIBUSB_CFLAGS@
+cgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @OPENCL_FLAGS@
 else
-cgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @OPENCL_FLAGS@ @LIBUSB_CFLAGS@ @LIBCURL_CFLAGS@
+cgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @OPENCL_FLAGS@ @LIBCURL_CFLAGS@
 endif
 
 cgminer_CPPFLAGS += $(ADL_CPPFLAGS)
@@ -41,7 +47,7 @@ cgminer_SOURCES := cgminer.c
 
 cgminer_SOURCES	+= elist.h miner.h compat.h bench_block.h	\
 		   util.c util.h uthash.h logging.h		\
-		   sha2.c sha2.h api.c usbutils.h
+		   sha2.c sha2.h api.c
 
 cgminer_SOURCES	+= logging.c
 
@@ -62,8 +68,8 @@ if NEED_FPGAUTILS
 cgminer_SOURCES += fpgautils.c fpgautils.h
 endif
 
-if NEED_USBUTILS_C
-cgminer_SOURCES += usbutils.c
+if WANT_USBUTILS
+cgminer_SOURCES += usbutils.c usbutils.h
 endif
 
 if HAS_BFLSC

+ 6 - 3
compat/Makefile.am

@@ -1,7 +1,10 @@
 
-if WANT_JANSSON
-SUBDIRS	= jansson
-else
 SUBDIRS	=
+
+if WANT_JANSSON
+SUBDIRS	+= jansson
 endif
 
+if WANT_USBUTILS
+SUBDIRS += libusb-1.0
+endif

+ 46 - 0
compat/libusb-1.0/AUTHORS

@@ -0,0 +1,46 @@
+Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
+Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+Copyright (C) 2008-2013 Nathan Hjelm <hjelmn@users.sourceforge.net>
+Copyright (C) 2009-2012 Pete Batard <pete@akeo.ie>
+Copyright (C) 2010 Michael Plante <michael.plante@gmail.com>
+Copyright (C) 2010-2012 Peter Stuge <peter@stuge.se>
+Copyright (C) 2011-2012 Hans de Goede <hdegoede@redhat.com>
+Copyright (C) 2012 Martin Pieuchot <mpi@openbsd.org>
+
+Other contributors:
+Alan Ott
+Alan Stern
+Alex Vatchenko
+Artem Egorkine
+Aurelien Jarno
+Bastien Nocera
+Brian Shirley
+David Engraf
+David Moore
+Felipe Balbi
+Graeme Gill
+Hans de Goede
+Hans Ulrich Niedermann
+Hector Martin
+Hoi-Ho Chan
+James Hanko
+Konrad Rzepecki
+Ludovic Rousseau
+Martin Koegler
+Martin Pieuchot
+Maya Erez
+Mike Frysinger
+Mikhail Gusarov
+Orin Eman
+Pekka Nikander
+Peter Stuge
+Rob Walker
+Sean McBride
+Sebastian Pipping
+Stephan Meyer
+Thomas Röfer
+Toby Peterson
+Trygve Laugstøl
+Vasily Khoruzhick
+Vitali Lovich
+Xiaofan Chen

+ 504 - 0
compat/libusb-1.0/COPYING

@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+

+ 5113 - 0
compat/libusb-1.0/ChangeLog

@@ -0,0 +1,5113 @@
+commit 09af2a25d7585c481f5e891ddfd1ceb2536ed6c9
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Mon May 6 20:55:53 2013 -0600
+
+    on to 1.0.16-rc10
+
+commit bcc159ec9156201544c249bb4a87f8f24cc34e0a
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Thu Mar 7 11:44:00 2013 +0000
+
+    Linux: Consume all events on a fd in one go
+    
+    * This fixes libusb_handle_events_timeout() only handling one event
+    * Fixes #123
+    
+    Conflicts:
+    	libusb/version_nano.h
+
+commit c703ab72d0398c18686c2970730cd580e2d1f46c
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Fri Oct 12 17:34:25 2012 -0400
+
+    Core: use C99 flexible array member when possible
+    
+    fix clang warning by using C99 flexible array member instead of zero
+    length array gcc extension
+    
+    Conflicts:
+    	libusb/libusbi.h
+
+commit 21e4c82043caf0d19ae9354e48035a135f3549d3
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Fri May 3 08:09:09 2013 -0600
+
+    bumb version to 1.0.16-rc9
+
+commit 66553c2e8219d84e3e8857b18341782e1ca82a58
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Fri May 3 08:03:37 2013 -0600
+
+    darwin: return LIBUSB_ERROR_NOT_FOUND when reading the active config descriptor when the device is not configured.
+    
+    fixes #172
+
+commit 42bb27b4fdc07e4c74a3ae8fa6ca67b66b591412
+Merge: 376a05a 629cefb
+Author: hjelmn <hjelmn@cs.unm.edu>
+Date:   Sun Apr 28 08:04:19 2013 -0700
+
+    Merge pull request #1 from LudovicRousseau/fixes
+    
+    Examples: fix compiler warnings
+
+commit 629cefbd40974c84c326107e3b31869088336753
+Author: Ludovic Rousseau <ludovic.rousseau+github@gmail.com>
+Date:   Sat Apr 27 22:40:03 2013 +0200
+
+    Examples: fix compiler warnings
+    
+    hotplugtest.c:30: warning: no previous prototype for ‘hotplug_callback’
+    hotplugtest.c:48: warning: no previous prototype for ‘hotplug_callback_detach’
+
+commit 376a05a9efa441b576fb1c58e5d49c90a1295e4a
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu Apr 25 22:31:01 2013 -0600
+
+    update to 1.0.16-rc8
+
+commit 20ec541f26d6d98f26d87cfca82287fe4bf15d30
+Author: hjelmn <Nathan Hjelm hjelmn@cs.unm.edu>
+Date:   Tue Apr 23 16:35:33 2013 -0600
+
+    darwin: clean up old code
+    
+    For some time only one type of completion message has been in use in the darwin
+    backend. The commit cleans up this code. This commit also removes some code
+    that has never done anything useful. If a pipe has an error it probably means
+    the device was closed so there is nothing to do.
+
+commit 9f41a3a780fc14785da2f07d03c119b8024b2452
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu Apr 25 21:12:45 2013 -0600
+
+    darwin: fix memory leaks in the darwin backend.
+    
+    There were two memory leaks in the darwin backend:
+     - A CFString allocated by IORegistryEntryCreateCFProperty in darwin_get_interface()
+       was not released.
+     - The runloop is retained by darwin_open() but was not release by darwin_close().
+
+commit e63fb62acfe52aecfd12b2a2f87f9a79495b2a0b
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu Apr 25 21:09:19 2013 -0600
+
+    core: release the context device list when the context is deleted.
+    
+    This commit fixes a memory leak in the context list patch. Devices need
+    to be unref'd when the context is deleted. This can happen if either 1)
+    the backend init fails, or 2) the context is destroyed by libusb_exit().
+
+commit 1c1d686151691f894c04519e2a4faec5811a292c
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Mon Apr 22 15:04:20 2013 -0600
+
+    Update .gitignore
+
+commit 6714fb46d2d2e74587637b465ceb967f5bf80901
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Fri Dec 7 19:59:39 2012 -0700
+
+    core: this is 1.0.16-rc7
+    
+    Rebasing lost the meaning of previous release candidates. Just set the
+    version to 1.0.16-rc7.
+
+commit eb2393972a1731571d3ca7f5b20fe3a3448a1675
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Thu Apr 11 10:19:03 2013 -0600
+
+    Add support for libusb_strerror()
+    
+    Fixes #102
+
+commit 34319ac4fd312356ae9488838b675e57e36c5f98
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Tue Apr 9 19:01:02 2013 -0600
+
+    Update release notes for 1.0.16 release.
+
+commit c3694edc25e0b63a9aa1c1f29590fb727a430aef
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Sun Apr 7 09:35:29 2013 -0600
+
+    darwin: don't need darwin_error_str if ENABLE_LOGGING is not defined
+
+commit eff69edbce89aa0364aba64e9944b83dcac5b080
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Sun Apr 7 09:22:48 2013 -0600
+
+    update AUTHORS
+
+commit c5ad994bb918bfbf87f8044197930124d2289d0f
+Author: Maya Erez <merez@codeaurora.org>
+Date:   Sat Apr 6 12:30:22 2013 -0600
+
+    Add definitions for Endpoint Companion and BOS descriptors.
+    Add APIs for parsing the Endpoint Companion and BOS descriptors.
+    
+    Nathan: Modified the original patch to fit the interface now already
+    provided by the FreeBSD implementation of libusb 1.0 and fit with
+    the rest of libusb.h.
+    
+    Some discussion: The FreeBSD API is not optimal. Further discussion
+    is needed to determine how to update the API without breaking code
+    that used the existing API. This discussion should probably involve
+    the FreeBSD developers and could be handled in a 1.0.x release.
+    
+    An example has been added to show how to use the new API.
+    
+    Fixes #110
+
+commit 55221eda77899ae1287a79c71138967029bed3b3
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Wed Apr 3 08:37:21 2013 -0600
+
+    Use AM_CPPFLAGS instead of INCLUDES in examples/Makefile.am
+
+commit 4232cd434b1475b09db2b15325840ea54753496b
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Wed Aug 22 11:47:00 2012 +0100
+
+    Linux: Avoid unnecessary splitting of bulk transfers
+    
+    * With the latest kernels it is no longer needed to always split large bulk
+      transfers into multiple urbs. This patch takes advantage of this by not
+      splitting when not necessary. Note that the non-split code path is in essence
+      using the old split code path with an urb count which is always 1.
+    * This leads to more sane handling of large transfers with recent kernels,
+      although our splitting code is well tested, not splitting at all still is
+      a lot better :)
+    * When used with a recent kernel, this also fixes the problems, on XHCI attached
+      devices, when a large bulk-in transfer ends with a short read in an urb other
+      then the last urb.
+    * For more on this see: http://marc.info/?l=linux-usb&m=133797554910355
+    
+    Conflicts:
+    	libusb/os/linux_usbfs.c
+    	libusb/version_nano.h
+
+commit ca257e3dbbecffe011ed3a5c87000ba634bf161d
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Wed Aug 22 11:47:00 2012 +0100
+
+    Linux: Add support for the new get_capabilities ioctl
+    
+    * There were a few (new) usbdevfs capabilities which libusbx could not
+      discover in any other way then checking the kernel version.
+    * However, this presents the following problems:
+      1) It is just not very pretty
+      2) Given the tendency of enterprise distros to backport stuff it is not
+         reliable
+      3) Some of these features turn out to not work with certain host controllers,
+         making depending on them based on the kernel version not a good idea
+    * Therefore a new USBDEVFS_GET_CAPABILITIES ioctl has been added to the kernel
+      to offer a better way to find out a device's capabilities (technically
+      the capabilities of the host controller to which the device is attached,
+      but that does not matter).
+    
+    Conflicts:
+    	libusb/os/linux_usbfs.c
+    	libusb/version_nano.h
+
+commit e922bc672aef38773818d2df41cf603b1eac9382
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Tue Apr 2 22:12:47 2013 -0600
+
+    darwin: don't assume an interval of 1 or high/super speed
+    
+    This patch updates submit_iso_transfer to use the bInterval value of the
+    endpoint and the speed of the device to determine the last frame of the
+    transaction.
+    
+    Fixes: #165
+
+commit 6abf49b40c38a5a911701e439160be8eea34f9f3
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Sun Feb 10 14:46:38 2013 -0700
+
+    windows: call usbi_sanitize_device to ensure the device descriptor gets cached
+
+commit 7533aa5ea10280add3d9223db2291089009d6988
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Fri Feb 8 20:41:43 2013 -0700
+
+    darwin: add fcntl.h
+
+commit 265ff59780a226100fcd0634e5c9b09dbe826f17
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Fri Feb 8 20:39:46 2013 -0700
+
+    Fix usbi_log_v in the case where ctx is NULL (no default context).
+    
+    Fixes #147.
+
+commit 854f7b63654045f20692f42b97dd6954b0069c74
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Fri Feb 8 17:19:01 2013 -0700
+
+    On windows do not set the hotplug pipe as non-blocking. I will leave it up the backend maintainers to figure out.
+
+commit 2fa98198472e54b2ae246fb33bf40130dea1456d
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Fri Feb 8 00:12:13 2013 -0700
+
+    darwin: add support for the LIBUSB_TRANSFER_ADD_ZERO_PACKET transfer flag.
+    
+    The zero-length packet is sent by the async event thread if all the following
+    conditions are met:
+    
+    1) The packet size is not a multiple of maxPacketSize, and
+    2) the transfer completed successfully.
+    
+    References #6.
+
+commit b8e6b77495dd8e25c0a52443db4fdc204d4f20f0
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Thu Feb 7 23:35:32 2013 -0700
+
+    Don't set the USBFS_URB_SHORT_NOT_OK flag on the last URB.
+    
+    Fixes: #142
+
+commit 1cd10590ae6fbfbd976349abe625e1495f6a1370
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Thu Feb 7 21:56:30 2013 -0700
+
+    darwin/libusb_reset: reenumerate device if the device descriptor or any
+    configuration descriptor has changed
+    
+    Some background: the Linux kernel causes a device to be reenumeration when
+    reset if the device's descriptors have changed. Darwin does not provide
+    this feature but instead provides a call to force the reenumeration of
+    a device. This behavior is required to support the firmware update
+    protocol used by some devices.
+    
+    This patch updates darwin_reset to check if either the device or
+    configuration descriptors have changed. If they have darwin_reset will
+    ask the OS to reenumerate the device and return LIBUSB_ERROR_NOT_FOUND
+    or LIBUSB_SUCCESS accordingly.
+    
+    Fixes #169
+
+commit 4920971837d569b7afa31f69ed7a92c313362cc3
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Fri Feb 8 17:10:24 2013 -0700
+
+    replace removed automake macro AM_CONFIG_HEADER with AC_CONFIG_HEADERS.
+    
+    Fixes #159. Thanks to cazfi.
+
+commit ed61beaa5ecb1bde41ad04060d980c4bc87d6936
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Fri Dec 7 19:55:21 2012 -0700
+
+    darwin: clean up extraneous includes
+
+commit 43ae35e6f482b5893348b75772c0e0866d050374
+Author: Nathan Hjelm <hjelmn@cs.unm.edu>
+Date:   Fri Nov 30 19:17:43 2012 -0700
+
+    darwin: dpriv->device will never be NULL for a valid device. remove unnecessary code that handled this case
+
+commit 9300dd929abf077c79cfbb0cb98022e9bedee3bb
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu Nov 29 16:19:11 2012 -0700
+
+    darwin: allow control messages on devices we can not exclusively open
+
+commit 046fae00f8a138f6d0c1ddba609676bc3a44e86c
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu Nov 29 16:14:03 2012 -0700
+
+    Add hotplug support to the Linux backend.
+    
+    There are two ways to configure hotplug support for Linux: udev, and netlink. It
+    is strongly recommened that udev support is used on systems that utilize udev.
+    We reenforce this recommendation by defaulting to --with-udev=yes at configure
+    time. To enable netlink support run configure with --with-udev=no. If udev
+    support is enabled all device enumeration is done with udev.
+    
+    References: #17
+
+commit e3948b8e39668f9242925622cccb0658404b5c32
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu Nov 29 16:13:00 2012 -0700
+
+    Add hotplug support to the Darwin backend.
+    
+    Hotplug events are handled by the async event thread. This thread listens for
+    two events: kIOTerminatedNotification, and kIOFirstMatchNotification. If
+    either of these events fires the thread will iterate through the appropriate
+    iterator and will either enumerate or call usbi_disconnect_device depending
+    on the event.
+    
+    While adding hotplug support it was discovered that when reading from the IO
+    registry we need to use kCFNumberSInt32Type for the device location. Using
+    kCFNumberLongType would cause locations to be sign-extended and not match
+    what is stored for the session id. This is now fixed.
+
+commit c6a7a0ebba3e0ea7e82ec75a8d63ff8604d78d25
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu Nov 29 14:23:26 2012 -0700
+
+    Add hotplug support. Bump the version to 1.0.15 and change the so version to
+    reflect external API changes.
+    
+    The internal API is changing as follows:
+     - Adding two new functions. usbi_connect_device, and usbi_disconnect_device.
+       Backends must call these functions to add them to the context's device list
+       at one of two places: initial enumeration (done at init), and on device
+       attach and removal. These functions need to be called once per context.
+     - Backends that support hotplug should not provide a get_device_list funtion.
+       This function is now deprecated and will likely be removed once all backends
+       support hotplug.
+    
+    The external API is changing as follows:
+     - Two new functions have been added to register and deregister callbacks for
+       hotplug notification: libusb_hotplug_register_callback(),
+       libusb_hotplug_deregister_callback(). Hotplug callbacks are called by
+       libusb_handle_events(). Details of the new API can be found in libusb.h.
+     - A new capability check has been added to check for hotplug support. See
+       LIBUSB_CAP_HAS_HOTPLUG.
+    
+    Aa suggested by Xiaofan add new example has been added to show how to use
+    the new external hotplug API. See examples/hotplugtest.c.
+    
+    References #17
+
+commit 0350974e585a018827b648b8e4d67c08cb19307f
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu Nov 29 13:53:41 2012 -0700
+
+    core: cache device descriptors in the core
+    
+    Discussion: It is necessary to cache the device descriptor in the core to
+    support reading the descriptors after a device is disconnected. We could
+    either 1) allow each backend to handle this caching (which would most
+    certainly duplicate code), or 2) cache the descritors when a device
+    is added. This patch does the later.
+    
+    Further discussion: It might be beneficial to cache more than just the
+    device descriptors in the core. It might also be worthwhile caching the
+    configuration and BOS descriptors as well.
+
+commit 8bf72124ad18461acedecc2d89adebc9b67e5b69
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Sun Sep 30 11:49:01 2012 -0600
+
+    core: Keep a list of contexts (active_contexts_list) created by libusb_init. The list can be used by backends to determine which contexts need notification of device removal (and in the future device arrival). The active_contexts_list is protected from multiple access by the active_contexts_lock.
+
+commit 2fff52d3f7bee6bae121846bc83cc41bea14e13e
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Tue Oct 2 08:07:03 2012 -0600
+
+    darwin: add support for detecting superspeed devices (IOUSBFamily 5.0.0 or newer)
+
+commit be5a526f6322c6200611f5495aed6d9fbb523b2e
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Sun Sep 30 10:22:30 2012 -0600
+
+    clean up tabs
+
+commit f9acbbd1a598213fe7d0bff2d06209d9af003558
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Fri Sep 28 22:13:09 2012 -0600
+
+    darwin: use Release instead of IODestroyPlugInInterface to avoid stopping
+    IOServices associated with a device
+    
+    Some IOService subclasses with actually stop if IODestroyPlugInInterface is
+    used to release the plugin interface. This is likely what causes the
+    keyboard and mouse to lock up. Using Release should prevent this from
+    happening.
+    
+    Fixes #139
+    Fixes #150
+    Fixes #153
+
+commit f28f03b081926fa081cef2fee9a409f7e4dc0240
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Fri Sep 28 21:18:36 2012 -0600
+
+    darwin: don't bother retrying or unsuspending Apple devices during
+    enumeration
+    
+    Some devices appear to cause the keyboard and mouse to lock up
+    after repeated enumeration. Try to avoid the issue by not attempting
+    to unsuspend Apple devices.
+    
+    Fixes #150
+
+commit bd7cd8e5e20d2999a31a11fca5eb32068acbcd2c
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Fri Sep 28 21:18:08 2012 -0600
+
+    darwin: reduce number of times libusb attempts to retrieve a device
+    descriptor during enumeration
+    
+    On failure it doesn't make sense to keep on trying to enumerate a
+    device more than a couple times. Reduce the number of tries from
+    10 down to 3.
+    
+    Fixes #151
+
+commit 7634714aa696175b08016b6f2185a75a2f55a113
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue Oct 23 09:46:02 2012 +0200
+
+    configure.ac: AC_SEARCH_LIBS(clock_gettime) to be able to add -pthread
+
+commit 2799d70e471c8ab02bfac6d4efe1149e3d5ba37a
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue Oct 23 09:41:31 2012 +0200
+
+    configure.ac: Move VISIBILITY_CFLAGS into AM_CFLAGS
+
+commit 62f9a648cf8a875f7572697321f4059b40ef357c
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue Oct 23 09:37:47 2012 +0200
+
+    configure.ac: Move THREAD_CFLAGS into AM_CFLAGS
+
+commit 29c5786bb26bbe62122b94ae17da6c1b286006be
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue Oct 23 09:27:25 2012 +0200
+
+    configure.ac: Use LIBS instead of PC_LIBS_PRIVATE
+
+commit 2b044abace76ba0095ee5dbc71a7dac75e8c8f05
+Author: Pete Batard <pete@akeo.ie>
+Date:   Wed Aug 22 01:32:10 2012 -0700
+
+    io.c: Handle >= 1 second transfer timeout in libusb_wait_for_event()
+
+commit 3b821d0a709c6b5b3094a763bb04e48ed0447050
+Author: Peter Stuge <peter@stuge.se>
+Date:   Wed Aug 22 01:32:10 2012 -0700
+
+    io.c: Handle >= 1 second transfer timeout in libusb_submit_transfer()
+
+commit b7ed26c7add5528b71a205b4f04c242d3cbeab54
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Aug 4 14:27:55 2012 +0200
+
+    INSTALL_WIN.txt: Correct Windows backend webpage URL
+
+commit cf60da545c915905869fa4007fcdc5faa75fdcbb
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Aug 4 14:26:43 2012 +0200
+
+    Windows: #include <windows.h> in header files
+
+commit 36962a408b07920f2fdd61dda6bef0e9e319e7d2
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Jul 29 06:22:45 2012 +0200
+
+    Windows: Remove msvc/inttypes.h
+    
+    This file might have been needed for platform abstraction, except that
+    all code shared among platforms doesn't need the file. Windows code in
+    particular does not need to use the file.
+    
+    The file was used in one single place, where the PRIu64 define has now
+    been replaced with it's value "I64u".
+
+commit 455b2d98869826db7276ddb69ce7b73f1acc9f94
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Jul 28 19:17:15 2012 +0200
+
+    libusb.h: Fix #145 libusb_ref_device() and libusb_unref_device() typos
+
+commit 53e526e21b519300aff9c9579f886cfc107b0a30
+Author: Simon Haggett <simon.haggett@realvnc.com>
+Date:   Tue Jul 10 16:07:45 2012 +0100
+
+    Windows: Stop leaking event handle when destroying condition variables
+    
+    usbi_cond_destroy() must close the handle created by usbi_cond_intwait().
+
+commit c5194b408286229ce0d94765f963890057d46ee0
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue Jul 10 16:54:16 2012 +0200
+
+    io.c: Avoid timerfd race condition between completion and new submit
+    
+    An event handler thread working on transfer completion for the last
+    flying transfer with a timeout can end up racing with a call to
+    libusb_submit_transfer() from a second thread, so that the timerfd
+    gets disarmed even though libusb actually again has a transfer with
+    a timeout.
+    
+    By arming or disarming the timerfd during completion strictly
+    according to remaining flying transfers while also holding the
+    flying_transfers_lock this change ensures that a new transfer can
+    not be added to the flying list until the completion code path has
+    armed/disarmed the timerfd according to the current flying list.
+    
+    Hans de Goede describes the race condition situation in
+    http://sourceforge.net/mailarchive/message.php?msg_id=29520709
+    
+    Signed-off-by: Peter Stuge <peter@stuge.se>
+
+commit 0845ff2aeed9ad009d246ecc2a945f007817ca9a
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue Jul 10 06:29:48 2012 +0200
+
+    .gitattributes: Set INSTALL_WIN.txt eol=crlf attribute
+
+commit cd8e76f0b1f47271c4059cd6c1e67e23f0e247a8
+Author: Pete Batard <pete@akeo.ie>
+Date:   Thu May 10 16:44:30 2012 +0100
+
+    Windows: Add INSTALL_WIN.txt
+    
+    libusbx.git commit 75b1cf81db74357f55cc4d0f596ef19a6a25c5cd
+    
+    [stuge: Remove trailing whitespace]
+
+commit 3bd6db0b8f60143836f5a933f35b15d764fbc7dc
+Author: Ludovic Rousseau <ludovic.rousseau@gmail.com>
+Date:   Wed May 9 09:13:41 2012 +0200
+
+    examples/Makefile.am: Use the implicit _SOURCES rule
+    
+    By default automake looks for a source file foo.c for a foo binary.
+    
+    libusbx.git commit 7e52e1e7534ead3f66b13bdcb28ac8587ff47ab0
+
+commit 1bd831c4e88857bff2f1670c89eda1d04da1cc54
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue Jul 10 01:46:38 2012 +0200
+
+    io.c: Only disarm timerfd when no flying transfer has a timeout
+    
+    Commit 4630fc22cff8ad3e1afa9b223378c0aabe282b5c made libusb work
+    correctly when built to use timerfd but run on a kernel without
+    timerfd support. The commit unfortunately also broke the logic
+    during transfer completion which decides if the timerfd will be
+    disarmed or not, and disarm_timerfd() was called even if the
+    timerfd had already been armed with the next flying transfer
+    timeout.
+    
+    Before the offending commit the timerfd would be disarmed only
+    when arm_timerfd_for_next_timeout() reported that there was no
+    flying transfer with a timeout. Let's restore that behavior.
+    
+    The bug was spotted through code review both by the author and
+    by Hans de Goede, but was not squashed until Vincent Pellier
+    experienced transfers never timing out, and helped confirm
+    the source of the problem. Many thanks!
+    
+    References #73.
+
+commit ae996af002793005db318689229300ff73549964
+Author: Ludovic Rousseau <ludovic.rousseau@gmail.com>
+Date:   Tue May 8 20:34:12 2012 +0200
+
+    Darwin: Fix warning: comparison between signed and unsigned
+    
+    libusbx.git commit c5c6b0e69a13786e48b2b6254c8e5458dc6716cc
+
+commit 0f29541c6728c9c2159080267b43e9b4144e9e56
+Author: Ludovic Rousseau <ludovic.rousseau@gmail.com>
+Date:   Tue May 8 15:53:56 2012 +0200
+
+    Core: Return LIBUSB_ERROR_IO on sync API TRANSFER_ERROR and _CANCELLED
+    
+    This is much more appropriate and also fixes gcc -Wswitch-enum warnings.
+    
+    libusbx.git commit 30ccbd773bc02d5dfd21e02bfba6d58234f59393
+
+commit 133092314d539d4c1a37997bb0c4ccfbcacb4677
+Author: Ludovic Rousseau <ludovic.rousseau@gmail.com>
+Date:   Fri May 4 16:56:00 2012 +0100
+
+    autogen.sh: Correctly pass arguments containing spaces to configure
+    
+    libusbx.git commit d20cd4f3573fe74d0ec5a4e1d60c9d291547ace4
+
+commit 8dc8b977d796b227f59eb5a7b247b38e27748d52
+Author: Ludovic Rousseau <ludovic.rousseau@gmail.com>
+Date:   Fri May 4 16:56:00 2012 +0100
+
+    autogen.sh: Exit script on first error
+    
+    libusbx.git commit c74fe3ab703a28c6d8c3755213e3736c5d1eb35e
+
+commit d8e35a560dfada578c6f6dea520d7d908b002001
+Author: Toby Gray <toby.gray@realvnc.com>
+Date:   Thu May 3 11:25:11 2012 +0100
+
+    Windows: Fix deadlock when submitting transfers
+    
+    The Windows backend needed to call usbi_fd_notification() from
+    submit_transfer() because a new event source is added for every WinUSB
+    transfer. This could cause a deadlock when attempting to lock the event
+    lock if another thread was processing events on the just-submitted
+    transfer.
+    
+    The deadlock comes about as the thread calling libusb_submit_transfer()
+    acquires the transfer mutex before trying to acquire the event lock; this
+    is the other order of lock acquisition from an event thread handling
+    activity on the just submitted transfer. This could lead to one of two
+    deadlocks:
+    
+    1) If the transfer completes while usbi_fd_notification() is waiting for
+    the event lock and the callback attempts to resubmit the transfer.
+    
+    2) If the transfer timeout is hit while usbi_fd_notification() is waiting
+    for the event lock then the attempt to cancel the transfer will deadlock.
+    
+    This patch fixes both of these deadlocks by having libusb_submit_transfer()
+    only call usbi_fd_notification() after having released the transfer mutex.
+    
+    This deadlock was always present in the Windows code, but temporarily
+    deleted by mistake in commit 6506013c6d4face34cfec79dd0584e9f528cbc6a
+    and later restored in commit 325a8416697cf69b9b926ed68720f12b1aedf940.
+    
+    libusbx.git commit 1ed09c7b2a5fc27c3cfea21740584879781bff67
+    
+    [stuge: Touch up commit message]
+
+commit b988c3d66e349b4f3c430410a42b6203f4fef80f
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Jun 3 21:28:13 2012 +0200
+
+    Clean up broken whitespace in list_for_each_entry() macros
+    
+    Introduced by commit aa77b02da65afb0332b9e6853dae9e4dcda00bfa.
+
+commit f651b2669c6ab0804d572650d79551bc2b70f525
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue May 8 19:50:17 2012 +0200
+
+    examples: Add sam3u_benchmark isochronous example by Harald Welte
+    
+    Copied with the author's permission under LGPL-2.1 from
+    usb-benchmark-project/host/benchmark.c in
+    git://git.gnumonks.org/sam3u-tests.git commit
+    74959f7ee88f1597286cd435f312a8ff52c56b7e
+    
+    http://git.gnumonks.org/cgi-bin/gitweb.cgi?p=sam3u-tests.git;a=blob;f=usb-benchmark-project/host/benchmark.c;h=74959f7ee88f1597286cd435f312a8ff52c56b7e
+    
+    An Atmel SAM3U test firmware is also available in the above repository.
+
+commit 3a69eff1aaf8e3242937bd7ecc94a60e7aa502cd
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue May 8 19:22:31 2012 +0200
+
+    examples: Only check for HAVE_SIGACTION once in Makefile.am
+
+commit d9dbb433f3f3b9787417e34316604d99cb72b188
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue May 8 19:19:28 2012 +0200
+
+    .gitignore: Add examples/ path to the examples
+
+commit a129732fb45fc424743f26f01c906e4514f11521
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue May 8 19:14:40 2012 +0200
+
+    examples: Use a common LDADD for all examples
+
+commit 325a8416697cf69b9b926ed68720f12b1aedf940
+Author: Uri Lublin <uril@redhat.com>
+Date:   Tue May 1 16:47:34 2012 +0300
+
+    Windows: Make new transfers correctly notify the event handling thread
+    
+    usbi_fd_notification() calls are added back into submit_*_transfer()
+    so that the event handling thread will be aware of new transfers.
+    
+    libusb.git commit 6506013c6d4face34cfec79dd0584e9f528cbc6a from
+    libusbx.git commit 4cccbed825fe1dc138121640a6497d7d05aac159 removed
+    these calls during the removal of the DYNAMIC_FDS Windows-specific
+    
+    [stuge: Rewrite commit message]
+
+commit 4674b4d137df2e2e49a1057c947888de8f37d6e8
+Author: Ludovic Rousseau <ludovic.rousseau+github@gmail.com>
+Date:   Fri Apr 20 22:25:38 2012 +0100
+
+    Linux: Fix warning: comparison between signed and unsigned
+    
+    libusbx.git commit 36a7119bf296cecd4e910bef86908fd782224960
+
+commit ab9cd5a7be637f7b793987971a706b1d11c27ded
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Apr 20 08:10:11 2012 +0200
+
+    libusb-1.0.9
+
+commit 696400ad83531bcf944c71164a46f9ccb6a33df3
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Apr 20 08:08:34 2012 +0200
+
+    AUTHORS: Update list of contributors
+
+commit 19f94537ea55586dd85f8d627fcfaa6173069ea1
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Apr 20 06:41:34 2012 +0200
+
+    AUTHORS: Add Martin Pieuchot as copyright holder
+
+commit 1a1c633d7912a2565f6af0c9294e10a759d40e05
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Apr 20 06:41:12 2012 +0200
+
+    AUTHORS: Add Hans de Goede as copyright holder
+
+commit 9477f793341d59cc861acb283e6cb03b5730ac91
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Apr 20 06:40:45 2012 +0200
+
+    AUTHORS: Add Peter Stuge as copyright holder
+
+commit 4b0dfe9770356af3c51103a9b3d63c5f8cc63d8b
+Author: Pete Batard <pete@akeo.ie>
+Date:   Mon Apr 2 15:47:53 2012 +0100
+
+    AUTHORS: Update Pete Batard's copyright years and email address
+    
+    libusbx.git commit f98eaca0985364be00fcfde3fd3884075092a4e9
+    
+    [stuge: Remove unrelated changes]
+
+commit 9f0ea78357b7b1654cb3e7de6ff57f5f378b68f1
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Apr 20 08:35:04 2012 +0200
+
+    AUTHORS: Update Nathan Hjelm's copyright years
+
+commit 8d38506ebc9fb57a40113e5a7739572a42b826d8
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Apr 20 06:36:08 2012 +0200
+
+    README: Add the BSDs, punctuation, mailinglist link, and remove Daniel
+
+commit 05cbe2de45806db309343cdf298d8569c55863e5
+Author: James Hanko <james.hanko@tridentmicro.com>
+Date:   Wed Oct 19 17:32:34 2011 -0700
+
+    Linux: Search for /dev/usbdev<bus>.<device> USB device special files
+    
+    If neither the (now deprecated) usbfs filesystem nor udev is available
+    then libusb searches for device nodes also in /dev where they may be
+    created if the kernel was built with the option CONFIG_USB_DEVICE_CLASS.
+    This helps on embedded systems such as Android, and all mdev users.
+    
+    Fixes #119.
+
+commit a806d169e6b5f675289cb9307fcd6b908edd9219
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Apr 20 04:32:47 2012 +0200
+
+    Add a timestamp in log messages
+    
+    Fixes #34.
+
+commit 03f4d40c748506c85f88427dd53afd5c663a2929
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Apr 20 02:24:44 2012 +0200
+
+    Include library version in the very first libusb_init() debug message
+
+commit 84d5eafd1f24a1c6f77f0c2a2ad40e1fbfdea381
+Author: Martin Pieuchot <mpi@openbsd.org>
+Date:   Thu Apr 19 13:33:36 2012 +0200
+
+    OpenBSD: Provide libusb_get_device_speed() data
+    
+    Because the different speed values used by the libusb and OpenBSD's
+    usb_device_info structure are compatible, keep the code simple and
+    just copy the value returned by the USB_GET_DEVICEINFO ioctl() call.
+    
+    Fixes #45.
+
+commit c145ec09732fac2eef53accc07314040d22b64a5
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Apr 20 00:11:01 2012 +0200
+
+    doc/Makefile.am: Remove username from SF web rsync upload command
+    
+    Commit c407a2d97b6f8715d3452257a0adac40a20178e6 did it for tarballs.
+    
+    libusbx.git commit ca159f15737e9097a4d031c9950f281c42af040a
+
+commit 6506013c6d4face34cfec79dd0584e9f528cbc6a
+Author: Pete Batard <pete@akeo.ie>
+Date:   Tue Apr 10 13:30:24 2012 +0100
+
+    Windows: Remove #define compile time options in the backend source code
+    
+    * The DYNAMIC_FDS, AUTO_CLAIM and FORCE_INSTANT_TIMEOUTS options
+      were introduced for development/testing and don't appear to be
+      used by the Windows backend users => remove them.
+    
+    libusbx.git commit 4cccbed825fe1dc138121640a6497d7d05aac159
+
+commit e291e369b975692dfa1a0f029244af597fa61220
+Author: Pete Batard <pete@akeo.ie>
+Date:   Tue Apr 10 13:05:37 2012 +0100
+
+    Windows: Warn on one libusb_get_device_list() memory allocation failure
+    
+    libusbx.git commit 24d595aa71e7fd0f14d40e933a33f852f7269c8b
+
+commit 2f40a03ea0552cd8b5ce3d7667b20dc04da061da
+Author: Pete Batard <pete@akeo.ie>
+Date:   Tue Apr 10 13:05:37 2012 +0100
+
+    Windows: Add textual error name to debug message on auto-release errors
+    
+    libusbx.git commit 24d595aa71e7fd0f14d40e933a33f852f7269c8b
+
+commit 3c7f85a49b42ac36c6d41294858518c554ac4694
+Author: Pete Batard <pete@akeo.ie>
+Date:   Tue Apr 10 13:05:37 2012 +0100
+
+    Windows: Silence warning about unused function guid_to_string()
+    
+    Commit 6b1982b1bd321b55698ce537e64648e8aec85f6f removed the #ifdef
+    around guid_to_string() but this ended up causing a warning when
+    the function wasn't being called. Add it back with correct _MSC_VER.
+    
+    libusbx.git commit 24d595aa71e7fd0f14d40e933a33f852f7269c8b
+    
+    [stuge: Rewrite commit message for libusb.git]
+
+commit eb55963a6b33799ea76c34f538f21e86f235ea62
+Author: Pete Batard <pete@akeo.ie>
+Date:   Tue Apr 10 13:05:37 2012 +0100
+
+    Windows: Base DUMMY_HANDLE on LONG_PTR instead of LONG
+    
+    libusbx.git commit 24d595aa71e7fd0f14d40e933a33f852f7269c8b
+
+commit d930865987de523061eca259a7fed11aea626831
+Author: Pete Batard <pete@akeo.ie>
+Date:   Tue Apr 10 13:05:37 2012 +0100
+
+    Windows: Prefer calloc() over malloc() and cast all allocations
+    
+    This silences VS2010 intellisense warnings on memory allocation.
+    
+    libusbx.git commit 24d595aa71e7fd0f14d40e933a33f852f7269c8b
+
+commit df35117ce58b74fa530baaaccc30adaf432398ea
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Apr 19 22:55:44 2012 +0200
+
+    Add libusb_get_version() API function
+    
+    Let's see how this will be used. Fixes #53.
+    
+    libusbx.git commit 37dfd16c8c2f36c81c86de303072def0dc405e32
+    
+    [stuge: Remove unrelated changes]
+    [stuge: Add struct libusb_version member rc for release candidate suffix]
+    [stuge: Add struct libusb_version member describe for git describe output]
+
+commit 29d5f63c5765f36ea65b55c4cd5f36e1f10a4dae
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Apr 19 22:25:07 2012 +0200
+
+    Windows: Rename VS2005 solution and add VS2010 project files
+    
+    libusbx.git commit fcad0941e52eb2fd6d57d3327f420db14dfabf0b
+    
+    [stuge: Remove xusb references]
+    [stuge: Add newlines at end of new files]
+    [stuge: Rename libusb_20??.sln to libusb_vs20??.sln]
+
+commit b217ec1f904c4382010a3a834a7c58d595b594cf
+Author: Pete Batard <pete@akeo.ie>
+Date:   Sat Mar 31 22:32:56 2012 +0100
+
+    libusb/Makefile.am: Fix missing DLL .def file from make dist
+    
+    libusbx.git commit 10dc1ea9a799b13b7423968130da812aa97289bf
+    
+    [stuge: Use EXTRA_DIST in libusb/Makefile.am instead]
+
+commit 54cb51d8417e0128eb9088bf628db138c9daa2a0
+Author: Pete Batard <pete@akeo.ie>
+Date:   Sat Mar 31 22:14:47 2012 +0100
+
+    Makefile.am: Fix msvc dir not being included in make dist
+    
+    libusbx.git commit a8a80b60a14e3a8269e42dedf34fda66da8e0e50
+
+commit 38d5ba472c6cb728ec818a0c8d964b632c8a7992
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Fri Mar 30 13:40:32 2012 +0100
+
+    Linux: Don't spam the console with 'device unconfigured' errors
+    
+    libusbx.git commit 3c968be61befc47d33562843e5479ff67303b0c4
+
+commit 93f14087b2e79d71ba1e53c0b9c7da655dd1258e
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu Apr 19 05:52:58 2012 -0600
+
+    Darwin: Silence warning: cast from pointer to integer of different size
+    
+    As per http://marc.info/?m=133483651109899
+    
+    Reported-by: Xiaofan Chen <xiaofanc@gmail.com>
+
+commit 0efc2086646200d8dee86cbbb1e98136383a05c3
+Author: Pete Batard <pete@akeo.ie>
+Date:   Thu Mar 29 23:21:25 2012 +0100
+
+    .gitattributes: Add export-ignore for .gitattributs and .gitignore
+    
+    This keeps the git files out of archives created by gitweb.
+    
+    libusbx.git commit 2250152b251243f75c951533ae7b1139a785cfe6
+    
+    [stuge: Removed unrelated whitespace changes]
+
+commit a7ef55c02f0116b94cb75831e5d90ad258c662f8
+Author: Pete Batard <pete@akeo.ie>
+Date:   Wed Mar 28 01:02:02 2012 +0100
+
+    Windows: fix Clang warnings about unused assignations
+    
+    libusbx.git commit c0e7b289fdb35687b90263b14426319d2b96b132
+
+commit ac8eed67e1595ee5a069623e48362d8a85dcb252
+Author: Pete Batard <pete@akeo.ie>
+Date:   Mon Mar 26 23:34:25 2012 +0100
+
+    configure.ac: LT_LANG([Windows Resource]) makes windres check redundant
+    
+    libusbx.git commit 4f9fd6a29a712b0e3312983e9ff153e6d7ed0822
+
+commit 89ce6f7d05dc8ff4a441a01b192d2e20857f6c48
+Author: Pete Batard <pete@akeo.ie>
+Date:   Tue Mar 27 00:03:07 2012 +0100
+
+    Windows: Bring .vcproj x86_64 output directories in line with x86_32
+    
+    libusbx.git commit abdb4437ea1897226076fa706651e350dba1cfd5
+
+commit 77743c6f5b3cfa2d06dcb32204bc65d8bd4fec80
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Fri Mar 9 11:31:11 2012 +0100
+
+    Linux: Fix a comment in handle_iso_completion()
+    
+    Fix the comment at the end of handle_iso_completion, we don't stop on
+    urbs / isoc packets with less data then requested, which is a good
+    thing since it is a normal condition for isoc transfers.
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+
+commit 5b87c2c7475a8d68270e19336afec0c5a08579ca
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Fri Mar 9 11:31:10 2012 +0100
+
+    Linux: Remove bogus status handling from handle_iso_completion()
+    
+    Remove a useless check+set of status because:
+    1. The check is always true; and
+    2. The new value is never used
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+
+commit e23d8f67eab947e5d41216e0139f0a50d1342ef8
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Fri Mar 9 11:31:09 2012 +0100
+
+    Linux: Translate isoc packet status codes to LIBUSB_TRANSFER_ codes
+    
+    During testing of my usbredir code I hit a scenario where my libusb
+    app was seeing EXDEV as status in the transfer's iso_packet_desc.
+    
+    This happened because we didn't translate linux negative errno errors
+    in each isoc packet's status to LIBUSB_TRANSFER_ status codes! This
+    patch adds these translations.
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+
+commit 7199bc2c9c351b553b6175a588237ee793719281
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Fri Mar 9 11:31:08 2012 +0100
+
+    Linux: Fix URB return code handling
+    
+    During testing of my usbredir code I hit a case where EOVERFLOW was not
+    handled in handle_control_completion(). Instead of just fixing this one
+    case I've audited (and fixed where necessary) all handle_foo_completion()
+    functions to know about all errors documented in
+    linux/Documentation/usb/error-codes.txt.
+    
+    Note that for handle_iso_completion() this patch actually removes the
+    handling of some codes, since these can never occur on an iso urb (they
+    can only occur on the iso packets included in the urb, see the next patch
+    in this series). Also, in case an unknown status is encountered on an iso
+    urb this patch sets the urb's status to ERROR rather then leaving it at
+    completed.
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+
+commit 98bc7b8d125c2756deadfc889dcefd4e6f2fcd02
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Fri Mar 9 11:31:07 2012 +0100
+
+    Don't print an error when libusb_cancel_transfer() fails with NOT_FOUND
+    
+    As stated in the documentation for libusb_cancel_transfer(),
+    LIBUSB_ERROR_NOT_FOUND is an expected return value for
+    libusb_cancel_transfer() under certain circumstances, so
+    printing an error every time this happens is undesirable.
+    
+    Even more so because under Linux IOCTL_USBFS_DISCARDURB sets errno
+    to EINVAL when the kernel can't not find the urb in the kernel's
+    urbs-in-flight list, which means that the urb has already completed
+    at the host controller level but it has not necessarily been reaped
+    yet. IOW under Linux libusb_cancel_transfer() may yield a result of
+    LIBUSB_ERROR_NOT_FOUND *before* the transfer's callback has been
+    called! In conclusion there is no way for applications to avoid
+    calling libusb_cancel_transfer() on already completed transfers,
+    and these errors can and do happen frequently for some USB traffic.
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+
+commit 4db8275da59996eb1c22d2e9e9c527fa58b288ad
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Fri Mar 9 11:31:06 2012 +0100
+
+    Linux: Fix cancel_transfer return value when cancelling a multi-urb transfer
+    
+    If we fail to cancel the last urb of a multi-urb transfer because it
+    has already completed (errno == EINVAL on DISCARD_URB), then the entire
+    transfer has already completed, so returning NOT_FOUND is consistent
+    with what the documentation for libusb_cancel_transfer() says.
+    
+    But if we've successfully cancelled the last urb, and then another urb
+    fails with errno == EINVAL, this means that we've still cancelled the
+    transfer, as it has only *partially* completed.
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+
+commit b22253ba9cbd399299b534a8c5e3bbac3f240963
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Apr 19 04:05:29 2012 +0200
+
+    libusb-1.0.pc: Mention OpenBSD and NetBSD in description
+
+commit 6aa0fc60d94e3123de230d3fbc9196814c0e466e
+Author: Peter Stuge <peter@stuge.se>
+Date:   Mon Apr 16 05:59:44 2012 +0200
+
+    io.c: Add debug message with the callback address on completed transfer
+
+commit de41604560a57b2279ac1d0a10b8192a9224d284
+Author: Xiaofan Chen <xiaofanc@gmail.com>
+Date:   Sun Apr 15 11:50:27 2012 +0800
+
+    Experimental support for NetBSD using the OpenBSD backend
+    
+    Signed-off-by: Xiaofan Chen <xiaofanc@gmail.com>
+
+commit 404054cb508881c9bd6bc575b66c4f509046b4af
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Apr 19 00:41:45 2012 +0200
+
+    configure.ac: Separate per-OS backend selection from per-backend settings
+
+commit 2eba7e4197cf9afa77451186e1a116ee3ae91adc
+Author: Xiaofan Chen <xiaofanc@gmail.com>
+Date:   Sun Apr 15 07:17:18 2012 +0800
+
+    Linux: Silence unused variable warnings when without CLOCK_MONOTONIC
+    
+    Signed-off-by: Xiaofan Chen <xiaofanc@gmail.com>
+
+commit bc790a9c414871cc1d33f1c7686048434a700e45
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Apr 7 05:20:36 2012 +0200
+
+    examples: Use snprintf() instead of sprintf() in dpfp and dpfp_threaded
+    
+    The OpenBSD C compiler generates a warning for every use of sprintf()
+    and for a good reason. Reported in http://marc.info/?m=133376187514495
+    
+    Reported-by: Xiaofan Chen <xiaofanc@gmail.com>
+
+commit bffa232dca51bcc41df71c5735fa56370b7509ad
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Apr 7 03:55:36 2012 +0200
+
+    OpenBSD: Fix warning: 'hpriv' may be used uninitialized
+    
+    As reported in http://marc.info/?m=133376187514495
+    
+    The variable would be used uninitialized when the internal list of
+    open devices is empty as obsd_handle_events() checks which device
+    the event fd belongs to, which can not actually happen, but if it
+    ever does happen then we will now return LIBUSB_ERROR_NO_DEVICE.
+    
+    Reported-by: Xiaofan Chen <xiaofanc@gmail.com>
+
+commit 6b1982b1bd321b55698ce537e64648e8aec85f6f
+Author: Moses McKnight <moses@texband.net>
+Date:   Fri Mar 30 21:53:20 2012 -0500
+
+    Windows: Fix build on VC++2003 which doesn't support variadic macros
+    
+    Change _MSC_VER tests to check for >= 1400 instead of > 1200 because
+    Visual C++ did not support variadic macros until VC++2005, as per
+    http://msdn.microsoft.com/en-us/library/ms177415%28v=VS.80%29.aspx
+    
+    Since usbi_dbg() is a function and not a macro with the old MS C
+    compilers the functions guid_to_string() and windows_error_str()
+    need to be compiled unconditionally, and the compiler should remove
+    the dead code when debug logging is disabled on newer compilers.
+
+commit 58ac0355e547080c82d02685a32480b891383d3d
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Mar 31 03:44:40 2012 +0200
+
+    Windows: Don't use a log function body macro for old MS compilers
+    
+    The duplication is a lot more straightforward than the previous LOG_BODY
+    macro, which also didn't handle the special debug case correctly. The
+    duplicated code is fortunately not very long.
+
+commit 76af4c99bd6122c1dd7b58858b669c919d8c8806
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Mar 22 01:52:59 2012 +0100
+
+    libusbi.h: Add IS_EPIN() IS_EPOUT() IS_XFERIN() and IS_XFEROUT() macros
+    
+    The macros make backend code a little simpler to read, since the
+    transfer and endpoint direction is checked in several places across
+    the supported platforms.
+
+commit e3d0a4cb9e2f9872c9fdbb22d7ded169e111fc8f
+Author: Peter Stuge <peter@stuge.se>
+Date:   Wed Feb 22 14:21:54 2012 +0100
+
+    Add LIBUSB_TRANSFER_ADD_ZERO_PACKET flag to indicate need for ZLP
+    
+    Some protocols which use USB require an extra zero length data packet
+    to signal end-of-transfer on bulk endpoints, if the last data packet
+    is exactly wMaxPacketSize bytes long.
+    
+    This flag allows applications to inform libusb about this requirement,
+    so that libusb can handle the issue transparently.
+    
+    At the moment the new flag is only supported on Linux, and submitting
+    a transfer with the flag set returns an error at submit time on other
+    systems. Hopefully implementations will soon follow for other systems.
+    
+    References #6.
+
+commit 7e0c747cc5ed0a31f38dff5eb5f03d4043b05ada
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Feb 19 06:58:16 2012 +0100
+
+    libusb.h: Add comma after last value in enums to ease future expansion
+
+commit c20ec7a927c05e0b960269751c26ab2b6e0b39ab
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Feb 19 05:39:33 2012 +0100
+
+    Linux: Rework bulk continuation check to generic kernel version check
+    
+    The old check_flag_bulk_continuation() tested for one specific running
+    kernel version. The new kernel_version_ge() instead allows to test the
+    running kernel version against major, minor and sublevel parameters.
+
+commit cf8f5a7be821099b143fcea8e4ba553daa22818b
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Feb 19 05:32:10 2012 +0100
+
+    OpenBSD: Correctly catch attempts to do isochronous OUT transfers
+    
+    LIBUSB_ENDPOINT_OUT is the value of the direction bit, which is 0 for
+    OUT transfers, so the previous condition could never evaluate to true.
+
+commit ae8e86cffb81858af5eeddbf2ea1aec6d55f573d
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Feb 19 00:42:20 2012 +0100
+
+    Darwin: Do not reject devices with product id 0x0000
+    
+    Fixes #128.
+
+commit 4630fc22cff8ad3e1afa9b223378c0aabe282b5c
+Author: Peter Stuge <peter@stuge.se>
+Date:   Mon Feb 13 16:59:51 2012 +0100
+
+    Do not call timerfd functions when timerfd is not being used
+    
+    When libusb was built with timerfd support but used on a system
+    without timerfd support the library would hang indefinitely on
+    completion of the first transfer, since timerfd functions were
+    being called unconditionally and the error returned when timerfd
+    was not being used caused a confused internal state.
+    
+    Many thanks to Ivo Smits for looking into the issue, proposing
+    an initial solution, and helping with testing! Fixes #73.
+
+commit c40f3df1efbb9232b525e5f675746762ca2304b8
+Author: Michael Plante <michael.plante@gmail.com>
+Date:   Sun Feb 12 13:49:35 2012 -0500
+
+    Windows: Fix MSVC6 IDE warning on line continuation in libusb-1.0.rc
+    
+    * libusb\libusb-1.0.rc(21): Could not find the file LIBUSB_RC.
+    * only shows up first time after opening workspace.
+    * shows up on either build or clean.
+    * not actually due to rc.exe, but prior to it.
+    * probably an IDE bug.
+    * does not show up when running an exported makefile.
+    
+    Signed-off-by: Michael Plante <michael.plante@gmail.com>
+
+commit 5526841023101bafa280755c3bd19fc44b9c32a0
+Author: Pete Batard <pete@akeo.ie>
+Date:   Sat Jan 7 23:30:23 2012 +0000
+
+    Windows: Add Renesas SuperSpeed support for libusb_get_device_speed()
+    
+    * tests conducted using a Renesas PCIE USB 3.0 controller and driver and
+      a mass storage USB 3.0 confirm that USB_NODE_CONNECTION_INFORMATION_EX
+      uses (undocumented) value 3 for SuperSpeed
+
+commit 3df437680f8f5406795ec5f32d96612d327b2ca4
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Feb 10 18:06:43 2012 +0100
+
+    autogen.sh: Try to use libtoolize before trying glibtoolize
+    
+    This helps on Mac OS X where an old glibtoolize is included in the
+    system and newer, manually installed, versions provide libtoolize.
+    
+    See also http://marc.info/?m=132490560131894
+
+commit 4afbc78fe09bfc3dd7a609e5f82e9272c9e6226d
+Author: Peter Stuge <peter@stuge.se>
+Date:   Wed Feb 8 15:54:21 2012 +0100
+
+    Rename the lsusb example program to listdevs
+    
+    This is intended to reduce confusion with the much more significant
+    lsusb utility which is part of the usbutils package.
+
+commit 57ab55159298b7057e0dd9b3854f7fd1550588ed
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Fri Dec 9 13:44:21 2011 -0500
+
+    core.c: Fix clang warning about useless store to a variable
+
+commit 32bbbd133e24c24d02646c0f7d1963404d4955f2
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Fri Dec 9 13:43:46 2011 -0500
+
+    Darwin: Clarify comments on event thread creation and termination
+
+commit 6cf3285a4e0dfaec0fe53b8eb6a9281e3c5bcb6c
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Fri Dec 9 13:43:46 2011 -0500
+
+    Darwin: Fix incorrect mutex protection of libusb_darwin_acfl global
+
+commit 662ced422cf1ffce68753296a81dccf87f3a1c57
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Fri Dec 9 13:43:46 2011 -0500
+
+    Darwin: Use retained runloop variable instead of CFRunLoopGetCurrent()
+
+commit 952a9bb6116afc69c4bae4714c2eb0713bf62a6d
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Fri Dec 9 13:37:22 2011 -0500
+
+    Darwin: Fix libusb_init() and libusb_exit() refcount race condition
+    
+    Use OSAtomicIncrement32Barrier() and OSAtomicDecrement32Barrier()
+    in darwin_init() and darwin_exit() to be thread safe.
+
+commit 721cc1c19fc8e88c4482ab3d1e8a34fa100c403c
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Fri Dec 9 13:33:28 2011 -0500
+
+    threads_posix.c: Fix prototype warning by including threads_posix.h
+
+commit f6ef0fca4b36657c1a0885c18cc4c4afcb4f7339
+Author: Dave Camarillo <dave.camarillo@gmail.com>
+Date:   Fri Sep 23 11:56:58 2011 +0100
+
+    Windows: Fix crash during enumeration with >= 64 connected devices
+    
+    * indexes were outgrowing the unref_list array before realloc,
+      resulting in out of bound access and crash.
+
+commit e280760331e8b39ad3530235653644654166b322
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Oct 26 16:31:13 2010 +0100
+
+    Windows MSVC6: Remove SetupAPI, AdvAPI32 and OLE32 dependencies
+    
+    * this ensures that libusb dependent applications only need
+      to link with libusb on Windows
+    * (copied from Pete's msvc08 mods to msvc6 by Michael)
+
+commit fa66c93253855c9146011a6854d65df6d390039f
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Dec 13 21:18:10 2011 -0500
+
+    Windows: Output an error message on calls to libusb_get_pollfds()
+    
+    Signed-off-by: Michael Plante <michael.plante@gmail.com>
+
+commit 637145ed29ee7c7b13ac45d10cf1f798fc06cbd9
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Thu Jun 3 22:14:20 2010 -0500
+
+    io.c: Fix comment since pthreads isn't the only threading libusb uses
+
+commit bb37939ab44a54a054f73e2f381808b12fb9cb33
+Author: Michael Plante <michael.plante@gmail.com>
+Date:   Mon Aug 2 19:59:12 2010 -0500
+
+    libusb.h: Cast in libusb_get_string_descriptor() to avoid MSVC6 warning
+    
+    On MSVC6 bitwise OR promotes to int, causing the warning.
+
+commit ca09754471acba9a22fe8fc09170e5660d1d5c5d
+Author: Michael Plante <michael.plante@gmail.com>
+Date:   Fri Dec 23 16:50:21 2011 -0600
+
+    Windows: guid_to_string() is only discarded when macro-usbi_dbg used
+    
+    * usbi_dbg encloses all references to guid_to_string
+    * MinGW/cygwin warn about an unused function, so the #if
+      squelches this warning
+    * MSVC6 uses a variadic function form of usbi_dbg instead
+      of a macro, so the compiler still "sees" guid_to_string
+      and it therefore needs to always be defined for MSVC6,
+      even if it's only a stub.
+    * So we define it if usbi_dbg is used OR if MSVC6 is used.
+    
+    Signed-off-by: Michael Plante <michael.plante@gmail.com>
+
+commit 8e15adcb0089882d10269ab77d35e193770ab90e
+Author: Pete Batard <pete@akeo.ie>
+Date:   Tue Nov 15 01:11:12 2011 +0000
+
+    Windows: Fix undefined datatype 'LONG_PTR' in MSVC6
+    
+    * issue reported by Elmi
+    
+    Signed-off-by: Michael Plante <michael.plante@gmail.com>
+
+commit 17ad642cae618cc09c5516612fa3880d4b6b8635
+Author: Pete Batard <pete@akeo.ie>
+Date:   Sun Nov 13 23:10:15 2011 +0000
+
+    Windows: Fix for MSVC6 preprocessor not accepting blank parameters
+    
+    * unlike later iterations of Visual Studio, MSVC6 does not accept
+      blank parameters on macro calls [eg. CALL(a, ,b)]
+    * blank params were used with the DLL_DECLARE and DLL_LOAD macros
+    * issue reported by Elmi
+
+commit c591a7cbf7dbc6fbb4368e65cf58a8cd02582aeb
+Author: Michael Plante <michael.plante@gmail.com>
+Date:   Tue Oct 26 11:39:38 2010 +0100
+
+    Windows: Switch MSVC6 .dsp project files from MBCS to Unicode
+    
+    * MBCS (which is different from UTF-8) only makes sense if
+      supporting Windows 95/98, which we don't
+    * (try to match Pete's vcproj changes in MSVC6)
+
+commit 536e424fd7d057fc3f20f9939f9de4572e51c815
+Author: Michael Plante <michael.plante@gmail.com>
+Date:   Tue Dec 13 21:39:40 2011 -0500
+
+    Windows: Add missing MSVC6 lsusb.dsp project file
+    
+    Signed-off-by: Michael Plante <michael.plante@gmail.com>
+
+commit c56828857eb7ba6fb4f7701693dbb3fe4e75d5f6
+Author: Martin Pieuchot <mpi@openbsd.org>
+Date:   Mon Jan 30 09:59:30 2012 +0100
+
+    OpenBSD backend
+
+commit d2285744c7fa4007bb411be354268209d350b0f2
+Author: Xiaofan Chen <xiaofanc@gmail.com>
+Date:   Fri Jan 13 18:07:34 2012 +0100
+
+    configure.ac: Darwin: Move -lobjc from LIBS to PC_LIBS_PRIVATE
+    
+    Since commit 40327cd134718475f6cec8935b856d4fdff2099c it is neccessary
+    to explicitly include -lobjc not only when linking libusb itself, but
+    also for programs linking statically against libusb. References #63.
+    
+    See also http://marc.info/?m=132505900202378
+
+commit 93b0e09d53ed1d177631af9182378492481a790a
+Author: Xiaofan Chen <xiaofanc@gmail.com>
+Date:   Fri Jan 13 13:04:00 2012 +0100
+
+    examples: Link only with ../libusb/libusb-1.0.la and not with -lusb-1.0
+    
+    Previous _LDFLAGS included both the freshly built libusb in ../libusb
+    and -lusb-1.0, where libtool would usually resolve the latter to an
+    already-installed libusb library in the system. The extra reference
+    to a second libusb library resulted in failure to build examples on
+    Mac OS X in some cases, and is plain wrong.
+    
+    See also the thread at http://marc.info/?m=132637593623667
+
+commit cdc5df8f1b206a7c19bc221e8a9a97d5d98deb85
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Jan 12 10:34:55 2012 +0100
+
+    libusb/Makefile.am: Avoid recursive variables in .rc silent-rule
+    
+    Not every make supports recursive variable expansion so some automake
+    versions complain about non-POSIX variable names ever since commit
+    70bec4a9f8ec28d36c731011fa24d37c74ad3523 which added support for
+    silent-rules in our rule to compile the Windows .rc file.
+    
+    This commit removes the recursive variables and instead uses the
+    simple and generic GEN message and associated variable.
+
+commit a8e2e7cab278fbfcba91909eaf762cf66da9eda5
+Author: Ludovic Rousseau <ludovic.rousseau+github@gmail.com>
+Date:   Sat Sep 24 18:27:54 2011 +0200
+
+    Core: Fix #122 warning: no previous prototype for ‘usbi_log_v’
+    
+    Declare the usbi_log_v() function before using it.
+
+commit e88ecb1e65604c222f82da586bb9e9066d66fbba
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Fri Oct 14 14:40:29 2011 -0400
+
+    Darwin: Set a name for the background thread on Mac OS X 10.6 and later
+    
+    The call to pthread_setname_np() makes it easy to identify the
+    background thread in the Xcode debugger and in crash reports.
+
+commit 60bad550dcb31a315a667a6614c52f712c82f45f
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Sep 22 21:42:35 2011 +0200
+
+    libusb/Makefile.am: Add libusb-1.0.rc dependency on version.h
+
+commit 70bec4a9f8ec28d36c731011fa24d37c74ad3523
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Sep 22 21:38:29 2011 +0200
+
+    libusb/Makefile.am: Make the libusb-1.0.rc rule support silent-rules
+
+commit fa9b682a638e54a4556ef6bd343ef56d6300a520
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Sep 22 21:17:37 2011 +0200
+
+    configure.ac: Enable libtool support for Windows Resource language
+
+commit 58c73ddca310f757fc7ca75197bf3d7ca58ce29a
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Mon Sep 19 12:52:44 2011 -0400
+
+    descriptor.c: Use size_t for minor 64 bit compliance improvement
+    
+    Fixes #121.
+
+commit 27ec326a9f1bff4481702b35f39897c65a5db586
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Mon Sep 19 12:42:33 2011 -0400
+
+    Darwin: Fix warnings about mismatched signed/unsigned compare
+    
+    References #121.
+
+commit 59cc79f2c8e5da41fe2c761bf1e1d9cd18ddac81
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Mon Sep 19 12:38:20 2011 -0400
+
+    Fix unused variable warnings when without timerfd and/or when on Darwin
+    
+    References #121.
+
+commit 1cc5b4a9fb984e83681ae5c797fa6b22bc20f809
+Author: Ludovic Rousseau <ludovic.rousseau+github@gmail.com>
+Date:   Fri Sep 16 18:07:56 2011 +0200
+
+    Correctly handle LIBUSB_TRANSFER_OVERFLOW in libusb_control_transfer()
+    
+    sync.c: In function `libusb_control_transfer':
+    sync.c:122: warning: enumeration value `LIBUSB_TRANSFER_OVERFLOW' not
+    handled in switch
+    
+    Fixes #120.
+
+commit c55f581f43885f8576d8e2ebf4d46cd7ff3c1030
+Author: Pete Batard <pete@akeo.ie>
+Date:   Mon Sep 19 16:01:37 2011 +0100
+
+    Windows: do not set altsetting 0 as part of libusb_release_interface()
+    
+    * pointed out by Travis Robinson and Xiaofan Chen
+    * similar to a change advised by Alan Stern for the Linux kernel:
+      http://marc.info/?m=122790204410765
+
+commit efd3fae8f95ef7797ecd4b5731b198f100007d6a
+Author: Pete Batard <pete@akeo.ie>
+Date:   Mon Sep 19 15:45:35 2011 +0100
+
+    Windows: fix communication with hubs
+    
+    * issue reported by René Haunstrup in http://marc.info/?m=130503019227814
+
+commit a8d1eb7963e5811e16e8fb7e157cf3a00d888347
+Author: Pete Batard <pete@akeo.ie>
+Date:   Mon Sep 19 15:41:39 2011 +0100
+
+    Windows: add USB 3.0 controller support
+    
+    * Windows 8, NEC/Renesas, TI, Fresco Logic, Etron, VIA, ASMedia
+      (some of which untested!)
+    * includes workaround for NEC/Renesas USB 3.0 root hubs
+
+commit 48a19497bdd14325738ac9197d8cf4ebe1daa2d4
+Author: Pete Batard <pete@akeo.ie>
+Date:   Mon Sep 19 15:28:03 2011 +0100
+
+    Windows: add static keywords and drop duplicated or unneeded code
+
+commit af407286ba2fd346755297e56e365d84b98090d5
+Author: Pete Batard <pete@akeo.ie>
+Date:   Mon Sep 19 13:59:46 2011 +0100
+
+    Windows: fix 'windows_error_str' defined but not used when not logging
+
+commit abc3143ba1989a48f62246c2afb0eb4c3c5f7917
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Sep 22 10:19:17 2011 +0200
+
+    libusbi.h: Silence unused context variable warnings when not logging
+
+commit 69b71c896a153a307360cf21be67b3b6e1e09a2d
+Author: Pete Batard <pete@akeo.ie>
+Date:   Mon Sep 19 13:06:22 2011 +0100
+
+    Windows: copy DLL file regardless of ddk_build.cmd dll argument case
+
+commit fdbac8971212bda3a42feeeaeb92fd8e49c7e904
+Author: Pete Batard <pete@akeo.ie>
+Date:   Sun Sep 18 20:06:45 2011 +0100
+
+    Windows: Add uint32_t typedef for old MSC so that DDK can build lsusb
+
+commit c471d55e909d84012f065715703dad454d1fa421
+Author: Vitali Lovich <vlovich@gmail.com>
+Date:   Fri Sep 16 08:53:25 2011 -0600
+
+    Darwin: fix port leak in darwin_clock_gettime()
+
+commit 477f3917f8c123e36993f9c0ba8156ca0f16ccfa
+Author: Vitali Lovich <vlovich@gmail.com>
+Date:   Fri Sep 16 08:50:40 2011 -0600
+
+    Darwin: remove unnecessary run loop invalidation during libusb_exit()
+
+commit f52094f37ccaff8137f5ce39867d2dba9b0f6bf9
+Author: Vitali Lovich <vlovich@gmail.com>
+Date:   Fri Sep 16 08:49:54 2011 -0600
+
+    Darwin: fix port leak during libusb_exit()
+
+commit 8a2f7b5c0520e6099f2c624cd0994c60867c1628
+Author: Vitali Lovich <vlovich@gmail.com>
+Date:   Fri Sep 16 08:48:28 2011 -0600
+
+    Darwin: fix potential leak on libusb_claim_interface() error
+
+commit b1ee2ef8d0b67dcc51c15742cb2decb386cffd9b
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Fri Sep 16 08:41:01 2011 -0600
+
+    Darwin: Fix #117 transfer size 64/32 bit issue for transfer callbacks
+    
+    The transfer size is now always truncated to 32 bits.
+
+commit c407a2d97b6f8715d3452257a0adac40a20178e6
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Sep 15 17:04:43 2011 +0200
+
+    Remove username from SF FRS rsync upload command
+
+commit cbc2d7b2de58cf5fb02d9e5a39be0870527f8632
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Sep 15 16:48:35 2011 +0200
+
+    Support release candidate versions in configure.ac and libusb-1.0.rc
+
+commit 384a528ed7adde935681313dacc5cd79e4be9ea1
+Author: Peter Stuge <peter@stuge.se>
+Date:   Thu Sep 15 16:32:47 2011 +0200
+
+    Tidy .gitignore a little
+    
+    There's no xusb, we need a glob pattern for matching .exe files, and
+    fpusb tarballs aren't very common in the libusb source dir.
+
+commit 9ad3643391a7fc6ce97aa77ffaf97d244fd9e613
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Wed Sep 14 10:53:48 2011 +0200
+
+    Docs: Clarify that libusb_handle_events_timeout() tv param can't be NULL
+    
+    The example code and API doc for libusb_handle_events_timeout() could be
+    interpreted as it being OK to pass a NULL pointer for the tv argument (I
+    interpreted it like that when I first started coding for libusb).
+    
+    This patch changes the docs to make it clear that one must always supply
+    a tv struct to libusb_handle_events_timeout.
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+
+commit e1c06fb070c1328a3b78c7da8b9e779d466edd97
+Author: Peter Stuge <peter@stuge.se>
+Date:   Wed Sep 14 08:23:43 2011 +0200
+
+    Makefile.am: Do not remove ChangeLog on make distclean, fixes #116
+    
+    [pbatard: Remove it on make maintainer-clean instead]
+
+commit 0c5bf03eb829e51dcf19562fc4f745937235ea51
+Author: Vitali Lovich <vlovich@aliph.com>
+Date:   Wed Sep 14 07:02:06 2011 +0200
+
+    Darwin: Reduce race likelihood between cancellation and device disconnect
+    
+    References #88. The race condition still remains, but this change
+    makes it less likely to trigger.
+
+commit 3e6e257f55156c4600f3116a0befba8cee62872a
+Author: Peter Stuge <peter@stuge.se>
+Date:   Wed Sep 14 04:00:33 2011 +0200
+
+    Document that libusb_get_device_list() can return any libusb_error code
+    
+    Fixes #87.
+
+commit 737ba04ea40f19564b445fbb489907529e75edc9
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Thu Jun 16 10:49:13 2011 +0100
+
+    Linux: Fix #81 URB double free race condition on device disconnect
+    
+    A submitted transfer that has just been failed by the kernel could be
+    picked up by an event handler to be cleaned up, where freeing of URB
+    memory would race with the submit function doing it's own cleanup and
+    freeing as a result of the submit failing.
+    
+    libusb_submit_transfer() always holds itransfer->lock, so the race can
+    be avoided by taking that lock also in the cleanup path and checking
+    that the URB memory has not already been freed before freeing it there.
+    
+    As http://libusb.org/ticket/81#comment:14 notes there is still another
+    possible, but unlikely, race condition between libusb_submit_transfer()
+    and an event handling thread. That will require more work to solve.
+    
+    [stuge: Add check in cleanup path that URBs have not already been freed]
+
+commit 1b0f758a334d78d3832d17d694ac0c931da36050
+Author: Peter Stuge <peter@stuge.se>
+Date:   Wed Sep 14 03:00:14 2011 +0200
+
+    Add libusb_error_name() API function
+    
+    Until we have i18ned error messages we can at least offer easy
+    translation from numeric error code to the error code's name.
+    
+    [hansg: switch() on enum to get a compiler warning if a case is missing]
+    [hansg: Better return value when called with an unknown error code]
+    [hansg: Fix DEFAULT_VISIBILITY in definition to compile on all platforms]
+
+commit e16805130a04b2642891e86b8f479e6343ca17da
+Author: Peter Stuge <peter@stuge.se>
+Date:   Wed Sep 14 02:30:18 2011 +0200
+
+    Add libusb_has_capability() API function
+    
+    Since it is currently not planned to change the filename of the libusb
+    library between libusb-1.0 versions at least on Windows systems it's
+    important to have a capability API.
+    
+    Currently there exists only one capability; LIBUSB_CAP_HAS_CAPABILITY,
+    which tests support for the libusb_has_capability() API.
+
+commit 2dc2fa2a56408e515d25359323b4ea2f1bbec14a
+Author: Sebastian Pipping <sebastian@pipping.org>
+Date:   Tue Sep 13 20:38:26 2011 +0200
+
+    Fix typos in introductory documentation
+
+commit 0a828082aeedc6d19b6de4e3b10cc9762352fa7f
+Author: Pekka Nikander <pekka.nikander@senseg.com>
+Date:   Tue Sep 13 18:57:43 2011 +0200
+
+    Linux: Add libusb_open() debug and error messages with the device path
+    
+    Fixes #109.
+
+commit 6583372125d73543fe0db9fdc59850b9c6aa50d9
+Author: Pekka Nikander <pekka.nikander@senseg.com>
+Date:   Tue Sep 13 18:52:36 2011 +0200
+
+    Add debug message with libusb_open() error code
+    
+    References #109.
+
+commit f797ecb3b4e653594f8ebc0c9d9e2ca579062779
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Mon Sep 12 18:11:20 2011 +0200
+
+    Document libusb_handle_events_completed() and _timeout_completed()
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+    [stuge: Note that the old racy functions should be avoided by new code]
+
+commit 6696512aade99bb15d6792af90ae329af270eba6
+Author: Graeme Gill <graeme2@argyllcms.com>
+Date:   Sat Sep 10 15:47:05 2011 +0200
+
+    Fix #56 race condition causing delayed completion of sync transfers
+    
+    The sync API had a race where it would check a condition to know if it
+    needed to call a libusb_handle_events() function. However, the check
+    was done outside of the lock that is held while the condition is set,
+    so another thread could completely serve whatever was needed to make
+    the condition true between it being checked and the event handler being
+    called. This situation would be detected after a libusb-internal timeout
+    of 60 seconds, after which the transfer would be completed without
+    error, but with significant delay.
+    
+    Original patch at http://marc.info/?l=libusb-devel&m=127252114815709
+    
+    Changes by Hans de Goede:
+    - Renamed the "race-proof" functions from libusb_handle_events*_check()
+      to libusb_handle_events*_completed()
+    - Drop r = 0 setting in libusb_handle_events_timeout_completed()
+      (to make both completed checking cases identical flow wise)
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+    [stuge: Simplify libusb_handle_events_timeout() change with a goto]
+    [pbatard: Fix _handle_events_timeout() and _completed() definitions]
+
+commit cfee5446cdb2974c1e90c7c379a365c495975aef
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Fri Aug 26 23:06:40 2011 -0600
+
+    Darwin: Use a condition to signal async thread ready in libusb_init()
+
+commit d1bd234f7e1b1ff4168b8f605e2038e87a0e361f
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu Jul 21 22:34:12 2011 -0600
+
+    Fix #64 use of reserved identifiers throughout libusb
+
+commit a97762a8a121de1ad3deb9e861088b69bb6a155b
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu Jul 21 22:31:09 2011 -0600
+
+    Darwin: fix libusb_get_device_list() and libusb_claim_interface() leaks
+
+commit 8723df191fcedc6161732fd06d12df392c6dea3f
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu Jul 21 22:28:47 2011 -0600
+
+    Darwin: use kIOMasterPortDefault instead of creating a master port
+
+commit 0eb7e43759003610d1afe6148aa6ff4f5859ccb0
+Author: Peter Stuge <peter@stuge.se>
+Date:   Wed Jul 27 03:15:03 2011 +0200
+
+    Allow devices with zero configurations to be discovered
+    
+    At least in Linux, wireless USB devices have zero configurations until
+    they have been authorized. This device state can be set for any USB
+    device using:
+    
+    echo 0 > /sys/bus/usb/devices/?-?/authorized
+    
+    An unauthorized device would previously make usbi_sanitize_device()
+    return LIBUSB_ERROR_IO, although there really was no I/O error.
+    
+    Reported-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
+
+commit 5010c3e80423d13acee6eeb4af974e8a9bcdd006
+Author: Peter Stuge <peter@stuge.se>
+Date:   Wed Jul 27 06:17:48 2011 +0200
+
+    Linux: Continue enumeration even if one device returns an error
+
+commit 2bf8848fb5c85ace0f445c0820a0c173cf76bf43
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Fri Jun 17 10:19:00 2011 +0200
+
+    Linux: Handle single- and two-digit kernel versions like 3.0 and 4
+    
+    The code has been tested with various version strings.
+    
+    [stuge: Remove bogus string length check and optimize for newer kernels]
+
+commit 0288bf24f91eca9f433ebad91a7eb6c0e3e29133
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Thu Mar 3 18:35:35 2011 +0000
+
+    Windows: Provide libusb_get_device_speed() data
+    
+    * use (currently superspeed unaware) USB_NODE_CONNECTION_INFORMATION_EX
+    
+    Fixes #45.
+    
+    [stuge: Explicitly convert OS device speeds to libusb device speeds]
+    [pbatard: Add breaks overlooked when adding explicit conversion]
+
+commit 382b7deaadd7e2f1d08c9e921e460bb3abf130b2
+Author: Trygve Laugstøl <trygvis@inamo.no>
+Date:   Tue Jul 19 23:20:40 2011 +0200
+
+    Darwin: Provide libusb_get_device_speed() data
+    
+    References #45.
+
+commit 44d6319f57e7e2c77347da228ed032e62716b438
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Thu Feb 17 15:06:40 2011 +0100
+
+    Linux: Provide libusb_get_device_speed() data from sysfs
+    
+    References #45.
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+
+commit c8c40bcbd22abca922ff31c4ed6a75fd7af78b59
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Thu Feb 17 13:17:55 2011 +0100
+
+    Add new API function libusb_get_device_speed()
+    
+    Reworked version of my earlier patch, largely modelled after (if not
+    copy and pasted from) Trygve Laugstøl's <trygvis@inamo.no> similar
+    commit 5a6541e0d80fb1f21e2b960bc2337a612f9d74fb in
+    git://git.libusb.org/libusb-trygvis.git
+    http://git.libusb.org/libusb-trygvis.git
+    http://git.libusb.org/?p=libusb-trygvis.git;a=commitdiff;h=5a6541e0d
+    
+    This patch does not add any OS specific code. The supporting code in
+    each backend follows in separate patches. References #45.
+    
+    Signed-off-By: Hans de Goede <hdegoede@redhat.com>
+
+commit 0db8cba7f2c372f0127c7df9724e5a35e93f2069
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Sun Mar 20 00:25:44 2011 -0600
+
+    Darwin: Improve device enumeration performance
+    
+    The device location is saved, and later used whenever iterating over
+    devices. Fixes #111 and #112.
+    
+    [stuge: Formatting fixes and split out libusb_get_device_speed() change]
+    [stuge: Combine with patch that uses the saved device location]
+
+commit 511ec4301deb516691e39e3df5b90fe28cb2bb0f
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Thu Feb 17 12:49:36 2011 +0100
+
+    Linux: Use __read_sysfs_attr() to get busnum and devaddr
+    
+    Remove code duplication.
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+
+commit e05bbc59ca7b896e2b825bde59bf883ac8c09f5c
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Thu Feb 17 12:45:10 2011 +0100
+
+    Linux: Add __read_sysfs_attr() helper function
+    
+    On Linux we often need to read (postive) integers from sysfs. This patch
+    adds a helper function for this. This is a preparation patch for adding
+    a libusb_get_device_speed() function to libusb.
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+
+commit 20e26dda0f86dafa3436b152e090b5f3410c8ce4
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Tue Feb 8 16:37:18 2011 +0100
+
+    Linux: Stop kernel from re-attaching in-kernel driver after reset
+    
+    When an interface is bound to the usbfs driver (iow claimed), the
+    kernel will unbind it, and then after the reset do a device_attach
+    on the interface, which will bind the default in kernel driver to
+    the interface.
+    
+    So if an app has detached the in kernel driver, and claimed the
+    interface and then does a libusb_reset_device. Things end up with
+    the interface no longer being bound to the usbfs driver (so no longer
+    claimed) and instead it is bound to the in kernel driver (iow the in
+    kernel driver is re-attached).
+    
+    We can stop this from happening by releasing all claimed interfaces
+    before the reset, as the kernel will not do the device attach after
+    reset, if no driver was bound to the interface before the reset.
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+
+commit 4e294dc9848aab86b31d2fff228cf97e7eadf913
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Thu Feb 17 12:35:46 2011 +0100
+
+    Core: Use USB_MAXINTERFACES rather then sizeof(claimed_interfaces)
+    
+    claimed_interfaces is a long and thus its size differs on 32
+    versus 64 bits, this patch uses USB_MAXINTERFACES instead of
+    sizeof(claimed_interfaces) on interface number range checks
+    for consistent behavior independent of the arch.
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+
+commit a68f956dd4c29d6ed799f04f07a3346317843999
+Author: Hans de Goede <hdegoede@redhat.com>
+Date:   Wed Feb 9 12:40:35 2011 +0100
+
+    Linux: Fix warnings seen when compiling with gcc-4.6
+    
+    Compiling with gcc-4.6 results in the following warnings:
+    os/linux_usbfs.c: In function 'op_get_configuration':
+    os/linux_usbfs.c:1144:6: warning: variable 'r' set but not used ...
+    os/linux_usbfs.c: In function 'op_handle_events':
+    os/linux_usbfs.c:2091:40: warning: 'status' may be used uninitialized ...
+    os/linux_usbfs.c:2044:6: note: 'status' was declared here
+    dpfp.c: In function 'save_to_file':
+    dpfp.c:228:9: warning: variable 'ignore' set but not used ...
+    dpfp_threaded.c: In function 'save_to_file':
+    dpfp_threaded.c:257:9: warning: variable 'ignore' set but not used ...
+    
+    This patch fixes these. (The second comes from handle_control_completion()
+    which gcc seems to inline into op_handle_events().)
+    
+    Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+    [stuge: Add fixes for dpfp examples and update source references]
+
+commit 209b5ccd827039b933b730e3f29abd0d72d3c6c6
+Author: Vitali Lovich <vlovich@aliph.com>
+Date:   Tue Jun 14 08:51:57 2011 +0200
+
+    Darwin: Fix #108 crash when a device is unplugged
+
+commit d3543e9140536a9751811b44f8496489be1e6bb7
+Author: Peter Stuge <peter@stuge.se>
+Date:   Mon Jun 13 22:58:23 2011 +0200
+
+    libusb.h: Add missing LIBUSB_CLASS_ codes currently defined by usb.org
+    
+    LIBUSB_CLASS_PHYSICAL
+    LIBUSB_CLASS_SMART_CARD
+    LIBUSB_CLASS_CONTENT_SECURITY
+    LIBUSB_CLASS_VIDEO
+    LIBUSB_CLASS_PERSONAL_HEALTHCARE
+    LIBUSB_CLASS_DIAGNOSTIC_DEVICE
+    
+    Per http://www.usb.org/developers/defined_class
+
+commit 08bc7ffb6a3b65afc6795cd048a890ee8da7d954
+Author: Peter Stuge <peter@stuge.se>
+Date:   Mon Jun 13 22:53:40 2011 +0200
+
+    libusb.h: Add LIBUSB_CLASS_IMAGE in addition to LIBUSB_CLASS_PTP
+    
+    The old LIBUSB_CLASS_PTP name is kept for compatibility. Fixes #106.
+
+commit 3d7938d85a33cd98553c0c898a8dd0490826b077
+Author: Peter Stuge <peter@stuge.se>
+Date:   Mon Jun 13 22:52:48 2011 +0200
+
+    libusb.h: Fix LIBUSB_CLASS_PRINTER description typo
+    
+    References #106.
+
+commit 5d0526af1a922afab02cdbdf4bb7078702759571
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Fri Feb 11 11:28:04 2011 -0500
+
+    Darwin: Fix #100 warning cast to pointer from integer of different size
+
+commit bb8854ff5680136e29b57505300f131c2646f258
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Mon Jun 13 22:26:43 2011 +0200
+
+    configure.ac: Fix #97 clang warning about -fgnu89-inline
+    
+    Remove the test that sets the flag since GNU89 inline semantics are not
+    required by libusb.
+    
+    [stuge: Also remove reference to the test result]
+
+commit cb3c2e488f298b78027c9d5fc0bec0e5ba27d761
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Wed Jun 15 01:38:58 2011 +0200
+
+    Windows: Make cancel_io() in poll_windows.c static
+    
+    References #97.
+
+commit 6635dbb4acb5ee556a020e431b15c954edfcbd29
+Author: Peter Stuge <peter@stuge.se>
+Date:   Mon Jun 13 22:21:02 2011 +0200
+
+    Windows: Make upperize() in windows_usb.h static
+    
+    References #97.
+
+commit 9479ce9dae3d0dbe2ce693bd02ccceb018a75fe9
+Author: Vitali Lovich <vlovich@aliph.com>
+Date:   Wed Mar 16 17:33:57 2011 -0700
+
+    descriptor.c: Fix buffer read overflow caught by valgrind
+    
+    In parse_interface() an unexpected descriptor would be parsed without
+    validating the descriptor's length.  It is possible for size to be 0 at
+    this point, which means that the parsing would read past the end of the
+    source buffer.  Fix #83 by checking the length of the remaining buffer
+    before parsing.
+
+commit c775c2f43037cd235b65410583179195e25f9c4a
+Author: Vitali Lovich <vlovich@aliph.com>
+Date:   Wed Mar 16 19:51:40 2011 -0700
+
+    Clean up in-flight transfers and device handle when closing a device
+    
+    Any in-flight transfers should properly invalidate their references
+    to device handles that are being closed.  Additionally, they should be
+    removed from the transfer-in-flight list.  This is done with the events
+    lock held to protect against another thread processing the same transfer.
+    The events lock is initialized as a recursive mutex, because the device
+    close code might itself be called while an event is being handled.
+    Fixes #82.
+    
+    [stuge: Trivial rework to reduce indenting]
+
+commit 74282582cc879f091ad1d847411337bc3fa78a2b
+Author: Vitali Lovich <vlovich@aliph.com>
+Date:   Wed Mar 16 19:43:30 2011 -0700
+
+    Add recursive mutexes to threading abstraction
+    
+    This is necessary for the device close path which needs to attain the
+    events lock, but which might itself be called while handling an event.
+    The events lock is necessary to properly clean up transfers which might
+    still be pointing to the device. References #82.
+    
+    [stuge: Move usbi_mutex_init_recursive() into threads_posix.c]
+    [stuge: Must also #define _XOPEN_SOURCE 500 to be able to build]
+    [pbatard: Un-inline usbi_mutex_init_recursive() to make Cygwin happy]
+
+commit 8f1bc0659136faf312dabe8fe67380a798299d33
+Author: Vitali Lovich <vlovich@aliph.com>
+Date:   Wed Mar 16 19:48:35 2011 -0700
+
+    Add USBI_TRANSFER_CANCELLING and _DEVICE_DISAPPEARED status flags
+    
+    The flags are used to indicate if a cancellation has started, and if
+    a cancellation has failed because the device is no longer available.
+    References #82.
+
+commit 87ba8a9ead4fd9e81ae3c5a894f698779de1f2c2
+Author: Vitali Lovich <vlovich@aliph.com>
+Date:   Wed Mar 16 19:50:04 2011 -0700
+
+    Linux: Detect and report that device has gone away while discarding URBs
+    
+    Return LIBUSB_ERROR_NO_DEVICE if the device is no longer available
+    (ENODEV) to discard the urbs. References #82.
+
+commit 2c85c363cddd72b9ab425f05e2ee03e0b1df24f1
+Author: Peter Stuge <peter@stuge.se>
+Date:   Mon Jun 6 02:46:46 2011 +0200
+
+    libusbi.h: Add comma after last value in enum usbi_transfer_flags
+
+commit 5d7be3e1337f2444097504931ac0f2f0997b2b05
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Jun 5 23:28:07 2011 +0200
+
+    threads_posix.h: Whitespace fix
+
+commit 18db4813e844fc6929680afcc9b793abcb06876a
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Jun 5 23:21:08 2011 +0200
+
+    libusb/Makefile.am: Correct threading files in libusb_1_0_la_SOURCES
+
+commit 5f30c81f66e8dd61f8eae16de548697708f9bd18
+Author: Alan Ott <alan@signal11.us>
+Date:   Thu Jul 21 16:37:48 2011 +0200
+
+    Linux: Fix #70 race condition in sysfs_get_device_list()
+    
+    Change the way libusb chooses between using sysfs and usbfs for information
+    about the attached devies.  Using the old method, a race condition could
+    occur if a device was unplugged just before (or during) the call to
+    libusb_get_device_list(), corrupting the internal sysfs_can_relate_devices
+    and sysfs_has_descriptors variables and preventing libusb_get_device_list()
+    from working in future calls.
+    
+    The old method was based on the assumption that if certain sysfs files
+    (eg: busnum) could not be opened, that indicated an inadequacy of sysfs
+    (ie: the running kernel's sysfs version did not contain those files),
+    when in reality those files couldn't be opened because the device had
+    been unplugged.
+    
+    The new method checks the adequacy of sysfs during libusb_init()
+    (op_init()) and if a sysfs file cannot be opened, it is now assumed that
+    it is because the device has been unplugged, not because sysfs is
+    inadequate.
+    
+    Signed-off-by: Alan Ott <alan@signal11.us>
+    [stuge: Include closedir() bugfix posted in ticket by Arne Laansoo]
+    [stuge: Remove dead code in sysfs_scan_device() found by Hans de Goede]
+
+commit 40327cd134718475f6cec8935b856d4fdff2099c
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Thu Feb 10 17:11:29 2011 -0500
+
+    Darwin: Fix #63 error when apps use Objective-C garbage collection
+
+commit 3ba2fae24886fec89410e5f2295f65363edcc2df
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Fri Feb 5 11:50:34 2010 -0500
+
+    Darwin: Fix #28 clang analyzer warning about unbalanced retain/release
+
+commit b67120f047f7eafa15c88c66fa61cef40805ec1f
+Author: Sean McBride <sean@rogue-research.com>
+Date:   Fri Feb 5 11:50:34 2010 -0500
+
+    io.c: Fix clang analyzer warning about unused variable
+    
+    References #28.
+
+commit 51af85d03a098d7d99ea544e8e9535b5476bab33
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue May 10 10:44:18 2011 +0200
+
+    .gitignore: Add m4 subdirectory created by libtool
+
+commit c569e5b3b314538f45d0b3b6f14ce3dbdfee1be9
+Author: Ludovic Rousseau <rousseau@debian.org>
+Date:   Mon Nov 15 14:45:50 2010 +0100
+
+    Linux: Do not include useless pthread.h
+    
+    The code does not use threads so no need to #include <pthread.h>
+    Fixes #74.
+
+commit 82af9f9d440ef49015652c699157cf62020f097a
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Mar 8 17:41:05 2011 +0000
+
+    Windows: minor code improvements
+    
+    * mostly warnings from VS2010's Intellisense
+
+commit 7e636dbe06001b9ac68e452a2fdc05e33fbb4e3a
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Mar 8 17:40:39 2011 +0000
+
+    Windows: prevent set_configuration request from being sent using WinUSB
+    
+    * multiple WinUSB set configuration requests can stall a device and
+      WinUSB does not support setting of alt configuration in the first place
+    * issue reported and investigated by Xiaofan Chen
+
+commit 578c50c99646e5ebbcfbea653524a519b843ebcd
+Author: Graeme Gill <graeme@argyllcms.com>
+Date:   Tue Mar 8 17:39:16 2011 +0000
+
+    Windows: fixed default WinUSB timeout and ineffective policy settings
+    
+    * default WinUSB timeout was 5 seconds, which may be to small.
+      PIPE_TRANSFER_TIMEOUT policy is now set to infinite for all EPs.
+    * other WinUSB policy settings were called before the endpoints
+      had been set. This is now fixed.
+
+commit 25fa63ea1cfe02e784cb62d3b869fd15e62b5b6e
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Mar 8 17:37:40 2011 +0000
+
+    Windows: Don't leak pipe fds
+    
+    use _open() and _close() rather than _open_osfhandle() and CloseHandle()
+    
+    * use of CloseHandle() prevented the pipe fds from being
+      relinquished on libusb_exit()
+    * leaked fds could lead to the OS running out of new fds
+      and LIBUSB_ERROR_NO_MEM being returned as a result
+    * using _open() avoids _open_osfhandle() redef for cygwin
+    * issue reported by Stephano Antonelli
+
+commit 3ccd9bddec316ee4b867959fd7f616eb4d410997
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue May 10 10:05:29 2011 +0200
+
+    Windows: enumeration overhaul
+    
+    * uses multiple passes in a single call
+    * uses a hash table, in anticipation for hotplug
+    * adds a (dummy) HUB interface for harmonization
+    * adds calloc on device struct creation in core
+      (to detect and avoid unnecessary double initialization)
+
+commit bb108cbe39802785d10fe025b74ca5ee19734151
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue May 10 00:56:18 2011 +0100
+
+    Windows: MS project files part 4 - MSVC6 project files
+    
+    Fixes #57 and #1.
+
+commit 78896ae99b9c2d5672fc93c5bad0f5e8e75c53ea
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue May 10 00:53:09 2011 +0100
+
+    Windows: MS project files part 3 - VS2005 project files
+    
+    References #57.
+
+commit 9e5f4277e379a82f5d32e81db1bd0ffaa6637596
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue May 10 00:38:49 2011 +0100
+
+    Windows: MS project files part 2 - WDK project files
+    
+    References #57.
+
+commit c1e75431418cdfc10ec963d823fce479cdae6840
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue May 10 00:38:12 2011 +0100
+
+    Windows: MS project files part 1 - support files & preliminaries
+    
+    * adds the MSVC support files used by MSVC6, VS2005 and WDK
+    * also adds missing defines required by MS compilers in libusb.h
+    * also anticipatory sets .gitattributes for CRLF handling
+    * also adds manually maintained .def file for import lib generation
+    
+    References #57.
+
+commit 85a14f43e0ce27cd47f84fdaeacbaa81cebdb886
+Author: Peter Stuge <peter@stuge.se>
+Date:   Mon May 9 08:12:24 2011 +0200
+
+    Move library version number from configure.ac to libusb/version.h
+    
+    This is neccessary to support native MS builds. The Windows resource
+    file libusb/libusb-1.0.rc must include the release version, which was
+    previously only available after configure had run and had substituted
+    the numbers into a generated libusb/libusb-1.0.rc file.
+    
+    The version atoms are now stored as CPP style #defines in libusb/version.h
+    so that the .rc no longer needs to be generated but can simply include the
+    header file and access the version information directly.
+    
+    The m4 macro LU_DEFINE_VERSION_ATOM() was added to configure.ac to get
+    version atoms from libusb/version.h for use in AC_INIT(). The macro
+    handles C and C++ style comments in version.h, but can easily be made
+    to fail by obscuring the file. Please don't do that.
+    
+    Tested with MinGW using autoconf, and manual compile of libusb-1.0.rc
+    using RC.EXE Version 5.2.3690.0 from Visual C++ 2005 Express Edition.
+
+commit 3481f52b014110f6c291e5a15e79ba774dcdfacf
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue May 10 08:36:32 2011 +0200
+
+    Windows: Debug builds create the same .dll file name as non-debug
+    
+    Thanks to Pete for pointing this out!
+
+commit 9da8cf5c9ed9bd381a77d8170fc0556edbcce4dc
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Mar 8 17:18:48 2011 +0000
+
+    Windows: explicit use of ANSI or WideChar calls
+    
+    * This is in anticipation of adding MSVC project files
+      that use Unicode rather than MBCS
+
+commit ae675c1f49dc00b695fce7296903f60998cc28ed
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Mar 8 17:16:23 2011 +0000
+
+    Windows: Remove SetupAPI, AdvAPI32 and OLE32 link-time dependencies
+    
+    * this ensures that libusb dependent applications only need
+      to explicitly link against libusb on Windows
+    
+    The run-time dependency on Cfgmgr32.dll, OLE32.dll and SetupAPI.dll remains.
+
+commit 356e312511e4892977636da52ec497ad2c716032
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Mar 8 17:12:33 2011 +0000
+
+    Add .gitattributes to avoid Windows line ending issues with autocrlf
+
+commit 61c120f025f3dee04eeb88159d7c0403a8bf91fe
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Feb 27 09:37:54 2011 +0100
+
+    Windows: Touch up FileDescription and ProductName resource strings
+
+commit 99b4ddcd893834a4be8b5884037b650e57ba0ba2
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Feb 27 07:20:40 2011 +0100
+
+    Windows: Remove emulated direct device access via HID API
+    
+    Either use a library such as HIDAPI to communicate with HID class
+    devices, or replace the kernel driver for the device with one that
+    offers support for the complete libusb API.
+
+commit 4be84ab49c838d534d3a1b8a64ffa89774984ee7
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Feb 27 06:59:15 2011 +0100
+
+    Revert libusb_strerror() until we have i18n and l10n
+
+commit 0e177f22fcc69d9aab6fb410e85f3413f478c94c
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Wed Jan 19 14:00:12 2011 +0000
+
+    dpfp_threaded: return instead of pthread_exit() to avoid Cygwin warning
+
+commit e65878f21b0a0bb96debcb292dc03ce3c4ebb701
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Wed Jan 19 13:52:08 2011 +0000
+
+    Windows: Rename various variables named "index" to avoid shadow warnings
+
+commit 019bf73bb2677dc7720bc8280527316adcbaa506
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Oct 5 12:50:53 2010 +0100
+
+    Windows: Fix logic in enumeration of driver name and port number
+
+commit 24494ed5db27737fc607fc35dda722521c9fe4d4
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Oct 5 12:50:13 2010 +0100
+
+    Windows: Allow claiming any interface in composite device using WinUSB
+    
+    Issue reported by Benjamin Dobell, see #48. The call to
+    WinUsb_QueryInterfaceSettings() is removed since it doesn't work
+    on any other interface but the first (a WinUSB limitation).
+    
+    This allows the use of WinUSB.sys in lieu of the usbccgp.sys
+    "USB Generic Parent" default driver for composite devices.
+
+commit 9c8e6545f2fbb171f81a9451eaf2d09e1fbc13b3
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Oct 5 12:47:15 2010 +0100
+
+    Windows: Allow arbitrary bConfigurationValue in config descriptors
+    
+    Unlike bInterfaceNumber, bConfigurationValue does not have to be
+    either sequential or contiguous. The bConfigurationValue is now
+    included in debug output. Fixes #48 reported by Benjamin Dobell.
+
+commit dcd002974e511879320233fd5b0600e06bdc5620
+Author: Thomas Röfer <Thomas.Roefer@dfki.de>
+Date:   Fri Nov 19 22:03:11 2010 +0100
+
+    Darwin: Schedule isochronous transfers further in the future
+    
+    This is required to make OpenKinect transfer data at 30 fps. This
+    change was originally made by Theo Watson, and Thomas improved on it.
+    The commit came via OpenKinect into libusb thanks to Kyle Machulis and
+    Hector Martin. Fixes #66.
+
+commit e83fad33dbaf9f37811da6d4cd9d3be554817944
+Author: Thomas Röfer <Thomas.Roefer@dfki.de>
+Date:   Fri Nov 19 22:03:11 2010 +0100
+
+    Darwin: Fix #65 memory leak in submit_iso_transfer()
+    
+    This was also independently fixed by Hoi-Ho Chan, but Thomas caught
+    an additional problem with his fix.
+    
+    This commit came via OpenKinect into libusb thanks to Kyle Machulis
+    and Hector Martin.
+
+commit 1a2d21fe42ad5a157651c787e2f500fc162c325b
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Feb 26 04:21:05 2011 +0100
+
+    configure.ac: Refactor Windows backend settings into one occurence
+    
+    The Windows backend is used both with MinGW and Cygwin, and since most
+    settings are identical they can be set in one place.
+
+commit 717f47621d18de16b87e237f3740299f43e4ca1c
+Author: Peter Stuge <peter@stuge.se>
+Date:   Mon Nov 15 19:58:51 2010 +0100
+
+    configure.ac: Rename AM_LDFLAGS to LTLDFLAGS and actually use them
+    
+    The new variable name tries to clarify that libtool is being used.
+    Linker flags must thus always be specified with -Wl.
+    
+    Factor out the libtool flag -no-undefined from host specific cases.
+    The flag is required to build a Windows DLL, but is correct also for
+    the other supported systems.
+    
+    Also, start actually using LTLDFLAGS in libusb/Makefile.am, so that
+    libtool will see the options set by configure.
+
+commit 3cbe5736469c1c52049752c137ae11387e9b079d
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Nov 21 23:38:46 2010 +0100
+
+    configure.ac: Clean up PC_LIBS_PRIVATE and AM_LDFLAGS
+    
+    Move linker options for when linking the library itself from
+    PC_LIBS_PRIVATE into AM_LDFLAGS. PC_LIBS_PRIVATE should only
+    contain flags needed to link applications statically against libusb.
+    Fixes #72.
+
+commit ef39d1510580b9fcbacf13443fa7a4e553a9a88e
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Feb 25 02:33:29 2011 +0100
+
+    configure.ac: Call AC_CONFIG_FILES() for each output file
+    
+    This avoids a problem with Windows line endings.
+
+commit 6e52ea067711e6e7e1b2882757fb61b11b6f8feb
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Nov 21 23:37:27 2010 +0100
+
+    configure.ac: Whitespace changes and trivial reordering
+
+commit 44b85dabc3f4efe0918a598f981675aa3765cc26
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Nov 21 23:10:35 2010 +0100
+
+    configure.ac: Quote AC_COMPILE_IFELSE() input
+
+commit 19d5882c398e49a453ff78494db23b7f4d13c37c
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Nov 21 23:09:02 2010 +0100
+
+    configure.ac: Define booleans to 1 when set, instead of an empty string
+    
+    This makes the generated config.h look a lot nicer.
+
+commit c24649d796c8b5c97af79a41856422def2e593bc
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Oct 30 22:28:59 2010 +0200
+
+    configure.ac: Clean up redundancy and fix LIBS on Linux
+    
+    LIBS, AM_LDFLAGS, OS_ conditionals and THREADS_POSIX had a bit of
+    redundancy throughout the file, and on Linux LIBS ended up missing
+    the -pthread flag.
+
+commit 0bd4a4dd89ff64b99ab55bfc0c5782502c10c676
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Feb 26 04:08:38 2011 +0100
+
+    configure.ac: Touch up Darwin and Cygwin OS messages
+
+commit 16cf11a1213272afd616598fa3aba0941e66ec3c
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Oct 30 22:13:05 2010 +0200
+
+    configure.ac: Do not use -pthread on Darwin
+    
+    It's not needed because Darwin has POSIX Threads in libc. Fixes #96.
+
+commit a120747d561929682cd0276ea4c13fb22fad8554
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Oct 30 22:07:37 2010 +0200
+
+    configure.ac: Check for poll.h, and for nfds_t on Darwin
+    
+    On Linux, assume nfds_t is always available.
+    
+    On Darwin, fall back to unsigned int when poll() exists but there
+    is no nfds_t, such as on Mac OS X before 10.4.
+    
+    On Windows (both MinGW and Cygwin), always use unsigned int instead
+    of nfds_t, and don't check for poll.h because we use our own poll()
+    implementation.
+
+commit 21d03d12f92c0d9bd7990861ca0ebf5009f82799
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Tue Oct 5 20:08:08 2010 -0600
+
+    Darwin: Add support for control requests on endpoints other than 0
+    
+    Signed-off-by: Nathan Hjelm <hjelmn@me.com>
+
+commit 9bfacd760b40f1137a7835198c6028cbdaddeb18
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Tue Oct 5 23:11:50 2010 -0600
+
+    Darwin: Add more error checking for libusb_open()
+    
+    Now also check the CreateDeviceAsyncEventSource() return code for errors.
+    
+    Signed-off-by: Nathan Hjelm <hjelmn@me.com>
+
+commit 478cd4a30728595fd742aa192d8149ee4216d4bc
+Author: Peter Stuge <peter@stuge.se>
+Date:   Wed Nov 3 21:46:53 2010 +0100
+
+    Core: libusb_get_next_timeout() must consider all flying transfers
+    
+    If transfer->flags indicated that a transfer had a timeout, but no
+    timeout was actually set, then libusb_get_next_timeout() would look
+    no further for a timeout, ignoring any transfers later in the list
+    which had a timeout set.
+    
+    Since libusb has an internal 60 second timeout this bug could not
+    cause complete lockup, but it could cause a 60 second timeout even
+    when a transfer was submitted with a shorter timeout.
+
+commit 7802e4a3e38bcefccf96ae510ec2c6b7a959b8b5
+Author: Ludovic Rousseau <rousseau@debian.org>
+Date:   Mon Nov 15 14:55:51 2010 +0100
+
+    Linux: Correctly catch read() errors for sysfs config descriptors
+    
+    read(2) returns ssize_t (signed) and not size_t (unsigned) or int.
+    
+    Silence "warning: comparison of unsigned expression < 0 is always false"
+    and fix #75.
+
+commit 4c7f3c8c3012bddba058afd2abdda792944fcda1
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Jan 23 04:01:25 2011 +0100
+
+    Linux: Refactor cancellation into one function for all transfer types
+
+commit 011f1f297bc134188fab9960da1b1b9f0bd541aa
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Oct 17 08:19:56 2010 +0200
+
+    Linux: Refactor discarding of URBs into a function and return all errors
+    
+    The Linux backend did not always return errors according to the
+    libusb_cancel_transfer() documentation.
+
+commit 26246df19cb4d88954a5aa9ed5f6b859e451df85
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Jan 23 04:01:01 2011 +0100
+
+    Linux: Set private number of URBs also for control transfers
+
+commit 295c9d12e25bc2dbdd8b42bd67a1f7120f0631a1
+Author: Alan Stern <stern@rowland.harvard.edu>
+Date:   Sun Oct 17 06:57:06 2010 +0200
+
+    Linux: cancel URBs in reverse order
+    
+    In a multi-URB transfer, URBs should be cancelled in reverse order of
+    submission. This prevents races that might otherwise occur (after URB N
+    is cancelled, data may be transferred for URB N+1 before it too can be
+    cancelled). Fixes #8.
+
+commit 07df377a5df25e9c1811b554dc00eb8c40e5b995
+Author: Alan Stern <stern@rowland.harvard.edu>
+Date:   Sun Oct 17 04:17:32 2010 +0200
+
+    Linux: report correct value for urb->actual_length
+    
+    Transferred bytes are returned correctly by the kernel for every URB,
+    even when an error occurs.  Hence they should always be included in
+    the transfer statistics.  The same is true for isochronous packet
+    length and status.
+    
+    [stuge: set itransfer->transferred so data is stored at correct offset]
+
+commit b26db49208c7a6ef0a99645142af21ce80c57c22
+Author: Alan Stern <stern@rowland.harvard.edu>
+Date:   Fri Oct 22 11:13:34 2010 +0200
+
+    Linux: improve reporting of URB error status codes
+    
+    Fix the way overflow errors are handled (they can occur in any
+    transaction, not just the last one in a transfer) and add tests
+    for other commonly-occuring error statuses.
+
+commit efc29733ad31f81883a7ac51a6cc6cda9ad4feb9
+Author: Alan Stern <stern@rowland.harvard.edu>
+Date:   Tue Oct 5 11:08:40 2010 -0400
+
+    Linux: improve detection of BULK_CONTINUATION kernel support
+    
+    Clarify the comments describing the BULK_CONTINATION flag, and improve
+    the subroutine that checks whether the flag is supported by making it
+    "future-proof", i.e., by working properly with kernel version numbers
+    higher than 2.6.
+
+commit bd267cf92269e0c4cd8eef795b91eefb2c63452e
+Author: Peter Stuge <peter@stuge.se>
+Date:   Mon Nov 22 05:14:00 2010 +0100
+
+    README: Update webpage URL and add Peter's email address
+
+commit 845b715675703c5f1bc907f6302ece416c9f112c
+Author: Peter Stuge <peter@stuge.se>
+Date:   Wed Aug 4 07:30:22 2010 +0200
+
+    libusb is not just for Linux!
+
+commit 67d9ef7b6877e17f2deec81cd41dc0948f6bed4b
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Tue Oct 5 19:48:39 2010 -0600
+
+    Remove USBI_OS_HANDLES_TIMEOUT and fix int/isoc timeouts on Darwin
+    
+    Backends set USBI_TRANSFER_OS_HANDLES_TIMEOUT for transfers instead.
+    Darwin only handles timeouts for bulk and control transfers, so the
+    backend now sets that flag accordingly, making libusb core handle
+    timeouts for interrupt and isochronous transfers. Fixes #31.
+    
+    Signed-off-by: Nathan Hjelm <hjelmn@me.com>
+    
+    [stuge: rework libusb_get_next_timeout() and enum usbi_transfer_flags]
+    [stuge: fix typo; set USBI_TRANSFER_TIMED_OUT flag correctly]
+
+commit 370922dfbe0964c0b8a0c1974bb1d7b85ac10607
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sun Nov 14 03:14:00 2010 +0100
+
+    Silence "warning: suggest braces around empty body in an 'if' statement"
+
+commit 0f85015bdf87f3bca0d86ed87c9b976176640922
+Author: Konrad Rzepecki <hannibal@astral.lodz.pl>
+Date:   Sat Nov 13 14:09:22 2010 +0100
+
+    Disallow libusb_get_string_descriptor_ascii() with index 0
+    
+    String descriptor 0 is the list of supported language IDs in the device,
+    which can't have an ASCII representation. Calling the function with
+    index 0 is thus not really useful. Fixes #43.
+
+commit 3b41c31d3fa2c1f93649cc5fc0f59acbf3efd5a1
+Author: Ludovic Rousseau <rousseau@debian.org>
+Date:   Fri Mar 19 15:35:14 2010 +0100
+
+    Use const for the usbi_parse_descriptor() format string
+    
+    Constant strings should be "const char *" instead of "char *". Silence
+    "discards qualifiers from pointer target type" warnings. Fixes #61.
+
+commit 7f2e9f0776386997d2b4c4c47598ab88e3caeb7a
+Author: Hector Martin <hector@marcansoft.com>
+Date:   Wed Aug 25 03:21:57 2010 +0200
+
+    Linux: Fix usbfs/sysfs config descriptor handling on big-endian
+    
+    usbfs endian-swaps, sysfs doesn't, not the other way around. Fixes #51;
+    descriptor endian parsing is backwards using sysfs on big-endian hosts.
+    usbfs is untested.
+    
+    Signed-off-by: Hector Martin <hector@marcansoft.com>
+    
+    [stuge: checked against Documentation/usb/proc_usb_info.txt]
+
+commit 2aa8984e59cf0f492e7fbebb8924f54f6160cc5e
+Author: Ludovic Rousseau <rousseau@debian.org>
+Date:   Tue Aug 17 20:53:04 2010 +0200
+
+    examples: #include <libusb.h> without directory name
+    
+    The libusb-1.0 directory name belongs in the compile command, e.g.
+    via pkg-config --cflags. Fixes #58.
+
+commit 7da756e09fd97efad2b35b5cee0e2b2550aac2cb
+Author: Ludovic Rousseau <rousseau@debian.org>
+Date:   Thu Jun 24 10:14:24 2010 +0200
+
+    Add missing argument to libusb_wait_for_event() documentation, fix #55
+    
+    In the libusb_wait_for_event() sample code in the section "Letting other
+    threads do the work for you" the call to libusb_wait_for_event() was not
+    updated by commit 1df713d622ab4f0b03aad72d903ac7beb8fb3b90, which added
+    the libusb_context *ctx parameter to the function, so the sample code
+    was broken until now.
+
+commit 678c242705b29f9cb6cc421b5625a6485ae58047
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Oct 16 14:22:30 2010 +0200
+
+    examples: Silence warnings about return value of fwrite()
+
+commit 9cd9059bf9baac69a9d6c909f4c1e000592fa260
+Author: Peter Stuge <peter@stuge.se>
+Date:   Sat Oct 16 11:47:14 2010 +0200
+
+    Linux: Don't free() URBs prematurely on hardware error; fix #54
+    
+    When an URB in a multi-URB transfer had an error, handle_bulk_completion()
+    would free all URBs and segfault once the next one completed, instead of
+    cancelling the remaining URBs and cleaning up as usual.
+    
+    This is basically the patch from the ticket, plus some restructuring
+    for increased readability of the function.
+    
+    Many thanks to Brian Shirley and National Instruments for finding and
+    fixing this!
+
+commit 116d34f608b02f4e14668450b158acf5db726f95
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Oct 5 12:43:41 2010 +0100
+
+    Windows: add support for filter drivers
+    
+    * precedence is driver > upper filter > lower filter, and defined
+      in struct driver_lookup lookup from set_device_paths()
+
+commit eb833fcd837e3aac2e497438b14c8612254c28ce
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Oct 5 12:36:49 2010 +0100
+
+    Windows: fix errcode shadow warning, and string and DLL_DECLARE fixes
+    
+    * use FormatMessageA, and overall improvement of windows_error_str()
+    * use safe_strlen() always
+    * better typing/init default
+    * more explicit debug message for devices with no driver
+
+commit 1feadb5f78e1d2cdfd2aaf0011e041c2848bae37
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Oct 5 12:29:32 2010 +0100
+
+    Windows: use IOCTLs for HID input, output and feature reports
+    
+    * fixes feature reports not providing actual read size
+      (reported by Axel Rohde http://marc.info/?m=127033070021994)
+    * removes the USE_HIDD_FOR_REPORTS macro
+    * IOCTL usage inspired from HIDAPI by Alan Ott
+
+commit d7c25451f4075d2a12eb5cbc91ff3de8c0292da0
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Mon Oct 4 20:03:58 2010 +0100
+
+    Fix libtool version setting
+    
+    This was being set too early to take effect.
+
+commit a6fb54e2eef4e393bd06829bc3bdc746ea9d41a6
+Author: Mike Frysinger <vapier@gentoo.org>
+Date:   Mon Oct 4 20:01:07 2010 +0100
+
+    Populate the pkg-config Libs.private field
+
+commit a9b4065f048e750b7317f6434406fd528b69bf33
+Author: Mike Frysinger <vapier@gentoo.org>
+Date:   Fri Aug 20 00:09:46 2010 -0400
+
+    Linux: fix build failure when CLOCK_MONOTONIC does not exist
+    
+    This is not available on all platforms.
+
+commit d192c5bd32736fde0080d756de6221287af34891
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Mon Oct 4 18:45:18 2010 +0100
+
+    Update libtool version info
+    
+    With input from various people on the mailing list, update the libtool
+    versioning info and start to update this on every release.
+    
+    The next libusb release will not need a change here. All following ones
+    will.
+
+commit e65f69a7ef3de357c867ddaac9598efe407078b6
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Thu Aug 5 16:40:09 2010 +0100
+
+    Updated documentation for unsupported Darwin/Windows calls
+
+commit c8bab4e19413d70c515a2eaf747a75b7f66fdc0b
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Sun Sep 19 14:24:25 2010 +0100
+
+    Windows: Make libusb_pollfd() return error
+    
+    Windows does not have numerical file descriptors but does have the
+    concept of event sources. Exposing these event sources will require
+    some careful thought and design, to be completed later.
+
+commit bd623f70d99fad8b975f8d4ee62ea4b1abf1272f
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Sun Sep 19 14:21:01 2010 +0100
+
+    MinGW: Use --add-stdcall-alias linker option
+    
+    Naming of symbols inside the library is inconsistent on Windows:
+    http://wyw.dcweb.cn/stdcall.htm
+    
+    Use this linker option to add aliases which add compatibility with
+    the "MSVC DLL" platform when a DEF file is used. It also better matches
+    the appearance of the Windows API itself.
+
+commit 29f9f9e3af3340df6a955881a93caf9d2a6d08d6
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Fri Aug 13 11:59:49 2010 +0100
+
+    Introduced calling convention (for Windows)
+    
+    Under Windows, a variety of compilers and configurations are available,
+    meaning that the manner of parameter passing (e.g. registers vs stack)
+    can vary.
+    
+    Match the Windows API calling convention and document this appropriately.
+    This calling convention will be used regardless of the configuration of
+    the user's development platform.
+    
+    The only user-level complication is that all functions used as libusb
+    callbacks must use the same calling convention as libusb. The
+    LIBUSB_CALL macro is provided to make this easy.
+    
+    Signed-off-by: Michael Plante <michael.plante@gmail.com>
+    Signed-off-by: Pete Batard <pbatard@gmail.com>
+    [dsd: slight change of strategy, add documentation]
+
+commit be523f1fe7c136c3fca06ae9c96aff44a22482ba
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Fri Aug 6 21:56:04 2010 -0600
+
+    Windows: fix string copy in sanitize_path
+    
+    The NULL byte was not being copied.
+
+commit 7fd36af9f749ce8bf96f89cefd519a9f46825573
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Fri Jul 30 00:30:31 2010 +0100
+
+    Windows: DuplicateHandle failure is not a warning
+    
+    This is because WinUSB handles are not duplicable, and generate a
+    lot of these warnings.
+
+commit 33cd2f68b4d500e852e354e5acae3d9a96a8ec26
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Fri Jul 30 00:23:05 2010 +0100
+
+    removed trailing whitespaces
+
+commit e47849afe9381c864683220eac9ce7bcf43f7883
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Wed Aug 4 18:18:32 2010 -0600
+
+    Windows: Mark interfaces as unused when releasing
+    
+    Without this important cleanup, the autoclaim code could attempt to
+    reuse an unclaimed interface as if it were already claimed.
+
+commit b30ca141a0bdce26e7cfdd91d346e49051532ee7
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Wed Aug 4 18:15:59 2010 -0600
+
+    Windows: fix device path string duplication
+
+commit e8d7a89503d5655c4b04da718c6971e25ff48162
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Mon Aug 2 21:27:38 2010 -0600
+
+    Darwin: Cache device configuration value
+    
+    Cache device configuration value to bring the Darwin backend more in
+    line with the libusb spec. To handle buggy devices GetConfiguration is
+    not called unless the device has more than one configuration.
+
+commit fe5d1d2050f715ffa8cbd35a378ac969a1a01584
+Author: Xiaofan Chen <xiaofanc@gmail.com>
+Date:   Fri Jul 30 15:56:43 2010 +0100
+
+    Fix inconsistencies between prototypes and definitions
+    
+    This removes some warnings on cygwin regarding a name clash against
+    the standard library "index" function.
+
+commit 3b538c43e11b805a37d93b6283d270d5d5f0d1f5
+Author: Hoi-Ho Chan <hoiho.chan@gmail.com>
+Date:   Tue Jul 27 21:04:17 2010 -0600
+
+    Darwin: handle kIOReturnUnderrun
+    
+    This return code indicates that the device returned a data packet
+    less than the max packet size. In libusb backend terms, this is
+    a successful transfer.
+
+commit 9a4249f8a104b98a15a7e3ba7ecae9a385ed9027
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Sat Jul 10 17:51:13 2010 -0600
+
+    Add Windows support
+    
+    Via Cygwin/MinGW, libusb now has windows support.
+    Thanks to contributors: Michael Plante, Orin Eman, Peter Stuge,
+    Stephan Meyer, Xiaofan Chen.
+
+commit d38dd5e3d2a872f7064eea084ddea8c33811dd7d
+Author: Hoi-Ho Chan <hoiho.chan@gmail.com>
+Date:   Sat Jul 24 13:48:00 2010 -0600
+
+    Darwin: write iso transfer details into correct packets
+
+commit fbff5b4b665ff2ebc948162617cf7f4f5d2fabeb
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Sat Jul 24 13:42:57 2010 -0600
+
+    Darwin: fix interface object leak
+
+commit dffc09835d6860ae9b6a62c39af5be346188cb05
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Sat Jul 24 13:41:03 2010 -0600
+
+    Darwin: clean up some debug messages
+
+commit 946d1abbca397b8e88a1b0b4df176dcc5e3b7348
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Sat Jul 24 13:39:16 2010 -0600
+
+    Darwin: Don't open devices during scan unless we have to unsuspend
+
+commit 3b6d9ac82e2599cad7817d21e909a42275ddc4c4
+Author: Peter Stuge <peter@stuge.se>
+Date:   Fri Jun 25 08:08:13 2010 +0200
+
+    Linux: Handle early complete of multi-URB transfer
+
+commit a516fcb99376686d2d0028e5ac69950c57a55b9e
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Wed Jul 21 17:49:21 2010 -0600
+
+    Only compile dpfp examples when sigaction is available
+    
+    It's not available on MinGW.
+
+commit a1d831ef82e1700f4ebb9df6ca5cef74be757c08
+Author: Aurelien Jarno <aurelien@aurel32.net>
+Date:   Tue May 25 09:32:19 2010 +0200
+
+    configure.ac: fix bashisms
+
+commit 7211aba6e290f9805e911959b2a43a4b3ec56d4f
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Fri Jun 25 12:01:58 2010 -0500
+
+    Only include sys/time.h on appropriate platforms
+    
+    This header doesn't exist on windows.
+    For libusb, determine at configure-time if the header is available.
+    For libusb.h, use gcc predefined macros to only include the header
+    on platforms that need it.
+
+commit b33c3cb9651459de1f3d549677cbac67a017a295
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Tue Jun 22 18:45:38 2010 -0500
+
+    Linux: Fix log message commit
+    
+    Forgot to test this.
+
+commit 139648d5723190734a51c1c66ddf41c3e87adf10
+Author: Ludovic Rousseau <rousseau@debian.org>
+Date:   Mon Jun 21 10:19:29 2010 +0200
+
+    Only initialize the default context when it is requested
+
+commit 22d61cd0891d8304dfc1a70579cf154fd8e6644a
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Tue Jun 22 18:20:23 2010 -0500
+
+    Linux: fix log message that was being unconditionally sent to stderr (#44)
+    
+    This message was put in place to aid libusb-compat-0.1 users, who
+    may run into the change that libusb-0.1 allowed you to usb_open() a
+    device that you don't have write access to, but libusb-1.0 does not.
+    
+    As explained on the ticket this change is dangerous so it should go through
+    the usual logging mechanism. I also added a similar regular log message
+    to libusb-compat-0.1.
+
+commit 82065a2c5e9d5ad0b2bb28792d12462f2fa150f0
+Author: Ludovic Rousseau <rousseau@debian.org>
+Date:   Thu Jun 10 18:41:27 2010 +0200
+
+    Fix 2 documentation typos
+
+commit 351c062aacdde0b0fa7972ee9b7c6b355dcee110
+Author: Ludovic Rousseau <rousseau@debian.org>
+Date:   Wed Apr 21 16:49:33 2010 +0200
+
+    add AM_MAINTAINER_MODE
+
+commit a7c056c14867e1cc3ef83682f2706cdbdca7c4ce
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Thu Jun 10 17:00:25 2010 -0500
+
+    Factorize event handler interruption code
+    
+    This will be additionally used by the windows backend which modifies
+    the fd set frequently.
+
+commit fc0af8e3f76925ad09e0fbc6d233d500753ee375
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Sat Jun 5 12:14:19 2010 -0500
+
+    Abstract low-level event handler operations
+    
+    The Windows backend uses something other than UNIX file descriptors
+    for event handling. Abstract out the operations to allow for this.
+
+commit 64383fb5b55a74b706967836e81cef61e57df86a
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Tue Jun 1 11:38:14 2010 +0100
+
+    fixes the possibility of using a broken timercmp on Windows
+    
+    Microsoft's implementation of timercmp does not work for >= or <=.
+
+commit f6d60a9a8fcf06629812da886e3a5de592624b61
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Mon Feb 1 19:26:13 2010 +0000
+
+    Switched to standard int pointer type for windows 64-bit compat
+    
+    On 64-bit Windows a pointer is 64 bit, but long is still 32 bit for
+    backwards compatibility.
+    uintptr_t nicely hides this difference and also works on Linux.
+    
+    [dsd: add appropriate include]
+
+commit a2fa855ce3795e31905b255267874af0603168bc
+Author: Michael Plante <michael.plante@gmail.com>
+Date:   Tue Mar 9 16:39:46 2010 -0600
+
+    added doxygen, dpfp, msvc, and xusb stuff to gitignore
+
+commit 845d96a9c30b6f053208ed6b5b5d4ad1655e2026
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Mon May 31 19:56:34 2010 -0500
+
+    Add reference counting to default context
+    
+    Michael Plante pointed out that if 2 users call libusb_init(NULL) within
+    a process, we end up creating 2 default contexts, one of which is lost.
+    
+    Add reference counting so that the default context is reused and
+    destroyed only after the last user.
+
+commit 0e77f017fd3d1bdec4aced0429a380d3e434081b
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Thu May 27 19:24:49 2010 -0400
+
+    Fix libusb_init() error handling
+    
+    9996ccaed7 introduced a problem in that mutexes could be destroyed
+    in the error handling codepath before they had been created.
+    Pointed out by Michael Plante.
+
+commit b03de9d07bf9a6b0c4e6cba9ec06b5271a22e621
+Author: Michael Plante <michael.plante@gmail.com>
+Date:   Mon May 24 11:57:10 2010 -0300
+
+    Modify log functions to compile with MSVC6
+    
+    MSVC6 does not support variadics.
+
+commit aa77b02da65afb0332b9e6853dae9e4dcda00bfa
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Sun Feb 14 19:46:05 2010 -0600
+
+    Add type parameter to the list_for_each_entry() and _safe() macros
+    
+    typeof() is a GCC extension, not supported by target compilers such
+    as MSVC.
+
+commit b92b16f437079208c8dfb1dc2380893846a07ee9
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Wed May 19 17:37:29 2010 -0300
+
+    Fix a usbi_pollfd leak in error path
+    
+    I accidently missed this when applying Pete Batard's earlier patch.
+    Pointed out by Michael Plante.
+
+commit 8aceb5c99056aaed6e6f2db1b303817e37e9fe8c
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Sun Feb 14 19:47:30 2010 -0600
+
+    Rename all interface parameters to usb_interface or interface_number
+    
+    Remove the use of the ambiguous "interface" where possible without
+    breaking the API.
+    'interface' is a preprocessor #define already associated with COM on Windows,
+    that can cause a conflict as soon as windows.h is included.
+    
+    There are a few more places where interface is still used, which should
+    be changed for libusb-2.0
+
+commit d7031ee8e1c449af23b2674fe18d9fc652c9bd80
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Mon May 17 19:30:27 2010 -0300
+
+    Stricter types and casts
+
+commit 9996ccaed740f8fcec4287a478ccaaa573f9865a
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Mon May 17 19:16:54 2010 -0300
+
+    Fixes to error handling and exit codepaths
+    
+    Various locks and things were being leaked/left open when handling
+    errors and during deinitialization.
+    
+    [dsd: small tweaks]
+
+commit 371ca4e440894bd1c845971418aa24c9d3919e63
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Thu May 13 19:38:05 2010 -0300
+
+    Darwin: Define IO_OBJECT_NULL if not already defined
+    
+    Needed on Mac OSX 10.3
+
+commit 7ba92cff94bbba19284749c614c26141d3023f37
+Author: Hans Ulrich Niedermann <hun@n-dimensional.de>
+Date:   Fri Jan 29 12:08:52 2010 +0100
+
+    libusb_cpu_to_le16: macro->static inline function
+    
+    The libusb_cpu_to_le16 macro was a ({ ... }) expression, which
+    generates the following compiler warning every time it is used,
+    (and that is several times for every #include <libusb.h>):
+    
+    libusb.h:880: warning: ISO C forbids braced-groups within expressions
+    
+    With this patch, #include <libusb.h> stops generating compiler
+    warnings on gcc 4.4.
+    
+    As libusb.h heavily relies on the use of static inline functions
+    those can be relied on to work properly, and there should not be
+    any significant difference in the code the compiler generates.
+
+commit 3473ac6c6fab32202d02d87679ebdb24e7d2df98
+Author: Francesco <francesco.montorsi@gmail.com>
+Date:   Tue Mar 9 16:35:35 2010 -0600
+
+    Add libusb_strerror() to get short error message in English from enum
+    
+    [dsd: small tweaks]
+
+commit 5b69f3b7b0610d5f518954792ddc93332a41d292
+Author: Michael Plante <michael.plante@gmail.com>
+Date:   Thu Feb 25 19:39:22 2010 -0600
+
+    Fix libusb_device::lock memory leak
+
+commit a636df4ca1b87ed3094a87828c022092a80ba613
+Author: Pete Batard <pbatard@gmail.com>
+Date:   Wed May 12 21:46:31 2010 -0300
+
+    Whitespace cleanup
+
+commit 23b5db8b3e353176dfa0635bfb6f0e2658f6e3de
+Author: Peter Stuge <peter@stuge.se>
+Date:   Tue May 11 00:51:43 2010 +0100
+
+    Add internal abstraction for POSIX Threads
+    
+    This prepares for a Windows backend without dependency on pthreads-w32.
+    
+    pthread_* is renamed to usbi_* and PTHREAD_* to USBI_*.
+    
+    A usbi_mutex_static_t and usbi_mutex_static_lock() and _unlock() are
+    introduced for statically initialized mutexes, since they may be
+    implemented using other types when pthreads mutexes aren't used.
+    
+    Move -pthread from libusb/Makefile.am to host-specific THREAD_CFLAGS in
+    configure.ac. This will enable optional use of -lpthread for cygwin.
+    
+    [dsd: minor tweaks, and roll in a change based on patches from Pete
+    Batard to only build dpfp_threaded example when we're using pthreads]
+
+commit a04cbb0095a78aeed3f65aaf06c46069d0ac184a
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Tue May 4 19:01:59 2010 -0300
+
+    v1.0.8 release
+
+commit 53b47299531974fa8901b74a163f3c8ebae4eec9
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Thu Apr 22 18:12:51 2010 -0300
+
+    Linux: don't set SHORT_NOT_OK on bulk out URBs (#20
+    
+    Setting this flag is illegal, and the behaviour we're looking for
+    is already in place for host-to-device transfers without this flag.
+
+commit 1519828b7ee1fce46d4c51fc097d52e01b8e0bb4
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Tue Apr 20 20:14:09 2010 -0300
+
+    Linux: Handle failure to read active configuration during enumeration
+
+commit 45168627cc15aee3875192f34286110dbbd27095
+Author: Nathan Hjelm <hjelmn@me.com>
+Date:   Tue Apr 20 19:43:06 2010 -0300
+
+    Darwin: don't reuse cached descriptors during enumeration
+    
+    Descriptor reuse was causing scans to return invalid information when
+    the device at a location has changed.
+
+commit 3af329db6dcbfb96d24867c757f9e125e5b7b0e5
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Mon Apr 19 19:36:55 2010 -0300
+
+    v1.0.7 release
+
+commit ceb8cacd6d2a4189de0db2ee46d45217511c69be
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Mon Apr 19 19:31:12 2010 -0300
+
+    Document that fd set contents are an internal implementation detail (#36)
+
+commit 9bea500b5747bdeba7c8251d45608558e71a1db5
+Author: Martin Koegler <mkoegler@auto.tuwien.ac.at>
+Date:   Mon Apr 19 19:22:46 2010 -0300
+
+    Linux: correct config descriptor endianness fix
+    
+    The seek_to_next_config codepath deals with both sysfs and usbfs;
+    make sure we only convert values in the usbfs path.
+
+commit 02df59a309e813c50b8230de99e69fb4e1814279
+Author: Martin Koegler <mkoegler@auto.tuwien.ac.at>
+Date:   Mon Apr 5 17:11:32 2010 +0200
+
+    Linux: Fix endianness handling of usbfs config descriptors (#27)
+    
+    driver/usb/core/devio.c function usbdev_read translate the follwing files
+    to CPU endianess:
+    
+    le16_to_cpus(&temp_desc.bcdUSB);
+    le16_to_cpus(&temp_desc.idVendor);
+    le16_to_cpus(&temp_desc.idProduct);
+    le16_to_cpus(&temp_desc.bcdDevice);
+    
+    All other data is passed without any change.
+    
+    libusb/os/linux_usbfs.c calls usbi_parse_descriptor with host_endian=1
+    for config descriptors. According to the kernel code, they must be
+    processed with host_endian=0, as they are not translated by the kernel.
+    
+    Signed-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at>
+
+commit ec303b01a5d4e51c000a283853af65059fa62285
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Tue Mar 23 16:22:08 2010 -0600
+
+    Darwin: fix enumeration of devices with non-consecutive addresses (#23)
+
+commit cd809e2f7cee3874b7ae16b2c482a8b63a90e4a5
+Author: Bastien Nocera <hadess@hadess.net>
+Date:   Mon Mar 8 10:50:51 2010 +0000
+
+    Add more interface classes
+    
+    As used in bluez.
+
+commit 1ce4aa67d849f5cad8a21072dc1c7b42158ce817
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Thu Mar 18 11:32:32 2010 -0600
+
+    Darwin: Cleanup async callback code, catch request timeouts
+
+commit 68af9f8d731f700267335941a8214d34ab518cc8
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Thu Mar 18 11:31:46 2010 -0600
+
+    Darwin: fix endianness of control setup packet
+    
+    IOUSBLib expects the control request to be in host byte order.
+    Swap the request into host byte order.
+
+commit cfce4d127184f4e4f334976151a0f80594bb5e22
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Mon Feb 15 14:10:08 2010 -0600
+
+    Darwin: fix memory leak in process_device
+    
+    Credit to Mike Colagrosso for finding this bug.
+
+commit 161893cfbefefe315f657677705abe090fc526f2
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Mon Feb 15 14:09:19 2010 -0600
+
+    Darwin: use logging functions
+    
+    Use usbi_warn, usbi_err, and usbi_info instead of _usbi_log.
+
+commit 2a72f38548208044dc3aa62681419d006c35732d
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Mon Feb 15 14:07:44 2010 -0600
+
+    Darwin: support multiple calls to libusb_init
+    
+    Credit to Orin Eman for finding this bug.
+
+commit a4186794d87124503db2f5f51f51ce90bb95daa7
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Sun Nov 22 17:20:53 2009 +0000
+
+    v1.0.6 release
+
+commit 8392ff22136fccaf1e15d186157609b8dd127bc5
+Author: Ludovic Rousseau <rousseau@debian.org>
+Date:   Sun Oct 25 10:06:41 2009 +0100
+
+    lsusb example: make print_devs() static
+    
+    lsusb.c:26: warning: no previous prototype for ‘print_devs’
+
+commit 9cc6bfaa15239bb6db1c1570b9beb6df2f848951
+Author: Ludovic Rousseau <rousseau@debian.org>
+Date:   Sun Oct 25 10:05:10 2009 +0100
+
+    Darwin: fix warning in darwin_error_str()
+    
+    os/darwin_usb.c:63: warning: return discards qualifiers from pointer
+    target type
+
+commit 4c706d2fb6b2c43b10d72ac5dff51cac4d939f1a
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Sat Nov 21 17:06:43 2009 +0000
+
+    Darwin: allow devices to be opened multiple times
+    
+    Allows libusb applications to access multiple interfaces of the same
+    device in the same application.
+    
+    Also fixes a set alt interface bug.
+
+commit 0232fc559cdacb9561f982dd6d28feb4435b3e4e
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Sat Nov 21 17:01:32 2009 +0000
+
+    Increase libusb_handle_events() timeout to 60 seconds
+    
+    The internal timing seems to be working, this will be a better test of
+    it before we make this timeout unlimited.
+
+commit 0bd7ef5d8697973a026c36c15d6276177b4ec4ea
+Author: Daniel Drake <dan@reactivated.net>
+Date:   Sat Nov 21 16:57:25 2009 +0000
+
+    Refine timerfd header check (#18)
+    
+    Require glibc-2.9 for the working timerfd support.
+
+commit 90d8fcab9018b8e6887a7e0592d1e5f692117234
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Nov 15 12:17:13 2009 +0000
+
+    v1.0.5 release
+
+commit 11d591058e3f105b0e90c23bbf58b18de691e690
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Nov 7 10:43:59 2009 +0000
+
+    Update documentation about early completion caveats
+
+commit f796c9528a71aa55326b6f0c9c7c5ec073d2bf92
+Author: Ludovic Rousseau <rousseau@debian.org>
+Date:   Sun Oct 25 09:59:51 2009 +0100
+
+    Add libusb_get_max_iso_packet_size() to libusb.h
+    
+    core.c:777: warning: no previous prototype for 'libusb_get_max_iso_packet_size'
+
+commit 4783008b7e711de9cb31631e60dda995f44068de
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Wed Oct 28 20:33:49 2009 +0545
+
+    Use timerfd for timeout handling
+    
+    Use a new file descriptor from the timerfd system calls to handle
+    timeouts. On supported systems, this means that there is less hassle
+    figuring out when the poll() timeout should be, since
+    libusb_get_next_timeout() will always return 0 and the timeout events will
+    be triggered as regular activity on the file descriptor set.
+    
+    Add API function libusb_pollfds_handle_timeouts() to detect whether
+    you're on a platform with the timing headache, and flesh out the
+    surrounding documentation.
+
+commit 9b120c2b3735566533c179aa8ca758fe45899a38
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Nov 7 10:03:07 2009 +0000
+
+    Use AM_SILENT_RULES for building
+
+commit ef6ea6c3ae38e4524f10e16e8cb88177d39c4826
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Nov 6 21:54:08 2009 +0000
+
+    v1.0.4 release
+
+commit 217f57617e0cff0d1bd6d726b243f04c6b179773
+Author: David Moore <dcm@acm.org>
+Date:   Fri Nov 6 21:37:25 2009 +0000
+
+    Linux: Add support for the new URB_BULK_CONTINUATION flag
+    
+    Add support for the new USBDEVFS_URB_BULK_CONTINUATION flag to libusb.
+    
+    This flag, which is expected to be available in usbfs starting with
+    kernel 2.6.32, allows the kernel to cancel multiple URBs upon receipt
+    of a short packet.  This capability allows libusb to preserve data
+    integrity of large bulk transfers that are split into multiple URBs.
+    Without this support, these URBs must be canceled in userspace upon
+    receipt of a short packet, a race condition against future transfers
+    which might partially fill these canceled URBs.
+    
+    This patch automatically detects whether a supported kernel is present
+    and enables the use of the flag when possible.
+    
+    [dsd: tweaks to supported kernel detection, and some inline
+     documentation of this mechanism]
+
+commit 69830057547396f893f0d7b3125a05d016313b10
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Wed Oct 28 15:13:22 2009 +0545
+
+    Transfer locking
+    
+    At least on Linux, there were some possible races that could occur if
+    a transfer is cancelled from one thread while another thread is handling
+    an event for that transfer, or for if a transfer completes while it is
+    still being submitted from another thread, etc.
+    
+    On the global level, transfers could be submitted and cancelled at the
+    same time.
+    
+    Fix those issues with transfer-level locks.
+
+commit 98f1b30d24359cb3185051b8df9ebb663cc10369
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon Sep 14 08:01:24 2009 +0100
+
+    Clarify that timeout 0 means unlimited timeout
+
+commit 858684f0dd25921e09565034a88709dbf6f6c61b
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Sep 11 22:09:12 2009 +0100
+
+    Linux: more flexibility with monotonic clock
+    
+    Some users have reported that CLOCK_MONOTONIC does not work on their
+    systems - I suspect it is available on x86 but perhaps not some
+    of the more uncommon architectures. We should fall back on
+    CLOCK_REALTIME in these cases.
+    
+    Also, CLOCK_MONOTONIC_RAW seems even more monotonic, so we should use
+    that if it is available.
+    
+    We now test different clock IDs during initialization to find the
+    best one that works.
+
+commit fe0d8dce1ed704915d501e7da700440c78144211
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Fri Sep 11 18:00:29 2009 +0100
+
+    Darwin: handle overflows
+
+commit f46716f42040986203fa6e873bfdabe1be2900ec
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu Aug 27 21:14:54 2009 +0545
+
+    v1.0.3 release
+
+commit 5b489b8b2a5aba7b8b804e5af6d2628735548238
+Author: Toby Peterson <toby@macports.org>
+Date:   Sun Aug 23 10:04:59 2009 +0545
+
+    Darwin: 64-bit type fixes
+
+commit ad8ae04d0b52009af0b1180e005f7554d2bbb26c
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Sun Aug 23 10:02:55 2009 +0545
+
+    Darwin: fix crash when reading descriptors after close
+    
+    Fix a crash which occurs if the user does the following sequence on a
+    device: open, close, get_configuration_descriptor.
+
+commit 45ae2aecf5512dcff059b2a416534e81c6a00c88
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Aug 1 13:55:15 2009 +0545
+
+    move bug info to bug tracker
+    
+    Protection needed: http://www.libusb.org/ticket/4
+    Losing data: fixed in previous commit
+
+commit 126129e174062c2a27423817a459e5113f777789
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu Jul 9 22:09:04 2009 +0100
+
+    Linux: try harder not to lose any data
+    
+    We would previously lose any data that was present on a cancelled URB.
+    Work harder to make sure this doesn't happen.
+
+commit 0334ee642b47dfe1ca9db64b22e7702ea14b3f09
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Jun 28 19:49:10 2009 +0100
+
+    Add libusb_get_max_iso_packet_size()
+    
+    As pointed out by Dennis Muhlestein, libusb_get_max_packet_size()
+    doesn't really do what the documentation might suggest because it
+    does not consider the number of transaction opportunities per
+    microframe.
+    
+    Add a new function to do what is useful for isochronous I/O.
+
+commit 615f18e64e96ae4ecc8e43d0de00933059a5209a
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Jun 20 22:33:21 2009 +0100
+
+    Linux: fix sending of zero length bulk packets
+    
+    Note that there are is a kernel bug preventing this from working
+    properly at the moment, even after this fix.
+
+commit 86f79fbf61c2018bdf009c7ebf92b38f3a16fd0c
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Fri Jun 19 22:18:44 2009 +0100
+
+    Darwin: Don't cancel transfers on timeout
+    
+    ...because the OS does this for us.
+
+commit d4bd9ed4de19a9c766f7a23eea8c852cdd61c18f
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Jun 14 19:23:21 2009 +0100
+
+    Don't terminate enums with commas
+    
+    g++ -pedantic doesn't like this
+    Reported by Eberhard Mattes
+
+commit 8be256082eb9bd8e243d89529f742926bb29a21b
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Jun 13 17:19:07 2009 +0100
+
+    v1.0.2 release
+
+commit 060e006e663fd59c281be29b71eb197e02b210e8
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Wed Jun 10 21:42:05 2009 +0100
+
+    Linux: fix config descriptor parsing on big-endian systems
+    
+    Multi-byte fields in the configuration descriptors that come back from
+    usbfs are always in bus endian format.
+    
+    Thanks to Joe Jezak for help investigating and fixing this.
+
+commit c4a905022f684da9a4a853eb9232a81a53df2652
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Sun Jun 7 22:29:35 2009 +0100
+
+    Darwin: improve handling of disconnected devices
+
+commit 6b69f54451762ef590b9c938ab000c07cf9099a3
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Sun Jun 7 22:26:37 2009 +0100
+
+    Darwin: fix parsing of config descriptors
+    
+    This was a confusion between configuration numbers and zero-based
+    configuration indexes.
+
+commit 2b3a9ffa776b383cb2dbc3c55e490e32e4c3c22b
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Jun 7 22:19:53 2009 +0100
+
+    Eliminate -Wsign-compare compiler warnings
+    
+    This was due to an API inconsistency which can be safely worked around.
+    Hopefully we'll remember to fix the API next time we come to break
+    things.
+
+commit cad5cb55c37137e94e35c74fdabfe42a5cbd229b
+Author: David Moore <dcm@acm.org>
+Date:   Wed May 27 23:15:54 2009 -0700
+
+    Make synchronous transfer APIs robust against signal interruption
+    
+    libusb_control_transfer and libusb_bulk_transfer are designed to be
+    synchronous such that control is not returned until the transfer
+    definitively succeeds or fails.  That assumption is violated if a signal
+    interrupts these functions because there is no way for the application
+    to continue waiting for the transfer without resubmitting it.  This
+    patch changes these synchronous APIs so they do not abort in the case of
+    a signal interruption.
+    
+    Signed-off-by: David Moore <dcm@acm.org>
+
+commit b501795985a23109f176d296e7b544b4c6354528
+Author: Alex Vatchenko <alex@fabulatech.com>
+Date:   Thu May 28 15:58:50 2009 -0400
+
+    pre-gcc-3.4 compatibility
+    
+    The -fvisibility and -Wno-pointer-sign options are not available on
+    old GCC versions.
+
+commit 00bb2805e994887f0a754a825c3ce03d22393386
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue May 26 15:53:26 2009 -0400
+
+    Fix memory leak in config descriptor parsing
+    
+    Pointed out by Martin Koegler.
+
+commit 068ff5b8a83fec0a9a91c80535a25b89a9ae64e8
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue May 12 19:20:51 2009 -0400
+
+    Update AUTHORS
+
+commit aa24c04e4043e39674b59ff0d302b2365cd0078f
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue May 12 19:03:37 2009 -0400
+
+    v1.0.1 release
+
+commit 44767677447fae4267131f99c591b14117486cac
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue May 12 19:01:44 2009 -0400
+
+    Add BUGS file
+    
+    Probably missed a couple of outstanding issues
+
+commit e0365a6f22e0e7f330ac931df031cf6f17f453d1
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Sun Mar 22 21:13:29 2009 -0400
+
+    Darwin: get_config_descriptor bugfixes
+
+commit 5fd0e8478240fece646a58a3c6114001a73be99f
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Wed Feb 25 12:33:33 2009 -0300
+
+    Fix compilation of Darwin backend
+    
+    My fault. Reported by ihryamzik@gmail.com
+
+commit b49f6bf5c910d0fd694ecf165d7927673707bff9
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Mon Feb 16 21:39:29 2009 -0300
+
+    Darwin backend
+
+commit d859158581e9a3250f36cdeeb8ea67cda04053bd
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Mon Feb 16 21:30:49 2009 -0300
+
+    Make endianness macros endian-independent
+    
+    Implementation suggested by David Moore. Needed for proper universal
+    code support on Darwin.
+
+commit 9196f58bdc8b9e967261df39865215faa5d39cfa
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Mon Feb 16 21:25:18 2009 -0300
+
+    Abstract clock reading into OS layer
+    
+    This will differ on Linux and Darwin, at least.
+    
+    [dsd: minor style tweaks]
+
+commit e91207860cac09b3afaafc4c14221b78d585c59a
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon Feb 16 21:20:28 2009 -0300
+
+    Fix endianness in device descriptors
+    
+    Pointed out by Nathan Hjelm.
+
+commit ccf6d3d2f6acf9b9a1cb5e1f1b03f382ae509b17
+Author: Nathan Hjelm <hjelmn@mac.com>
+Date:   Mon Feb 16 21:13:52 2009 -0300
+
+    Only link with librt on Linux
+    
+    [dsd: tweak configure.ac change]
+
+commit 894539931e4b4bd85708fe98b956049243cd6fb0
+Author: Hans Ulrich Niedermann <hun@n-dimensional.de>
+Date:   Mon Jan 26 00:31:48 2009 +0100
+
+    API docs: describe libusb_transfer_cb_fn type
+    
+    Add some text describing the libusb_transfer_cb_fn function type
+    with the semantics I have gathered from reading other parts of
+    the API docs, referring to the proper section for more details.
+    
+    [dsd: tweaked the description slightly]
+
+commit abe34a2656f8f9f21e53603796c536585e6233ef
+Author: Hans Ulrich Niedermann <hun@n-dimensional.de>
+Date:   Sun Jan 25 18:21:59 2009 +0100
+
+    Make empty array in struct compatible with C99
+    
+    If the compiler is known to be running in C99 mode,
+    use "flexible array members" ("foo[]").
+    
+    If the compiler is running in any other mode, continue
+    using the non-standard but widely common "foo[0]" syntax.
+
+commit 620075c7400764d9bb539b5c02065c45c2e8251e
+Author: Hans Ulrich Niedermann <hun@n-dimensional.de>
+Date:   Sun Jan 25 18:20:45 2009 +0100
+
+    Avoid signedness errors in API docs example code
+
+commit c754ae294cfe96ec4738d6641137c9e6c56330c7
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Jan 17 00:25:40 2009 +0000
+
+    Decrement poll() result when internal pipe has been handled
+    
+    When we receive data on the internal control pipe, we need to correctly
+    decrement the number of ready file descriptors before passing on the
+    remaining work to the OS implementation.
+
+commit b9ca960f2ba271d2b1a58e22b7c70464d69f6c8a
+Author: David Moore <dcm@acm.org>
+Date:   Sun Jan 11 21:46:17 2009 -0800
+
+    Prevent transfer from being submitted twice or improperly canceled
+    
+    This ensures that tpriv->urbs and tpriv->iso_urbs are always set to NULL
+    whenever a transfer is not submitted.  In this way, submit_*_transfer()
+    and cancel_*_transfer() can error check to ensure that the transfer is
+    in the correct state to be either submitted or canceled, preventing
+    potential memory leaks or double frees.
+    
+    Signed-off-by: David Moore <dcm@acm.org>
+
+commit d2a8ec2da8abcd8f4648ed118da16191011982dd
+Author: David Moore <dcm@acm.org>
+Date:   Wed Jan 7 22:31:09 2009 -0800
+
+    Linux: Fix race condition in cancel_bulk_transfer()
+    
+    This fixes a race condition in cancel_bulk_transfer().  In the old
+    version, awaiting_reap and awaiting_discard are incremented in
+    cancel_bulk_transfer() and decremented in handle_bulk_completion().
+    However, since these events may take place in two different threads,
+    these variables may reach zero before all URBs have been canceled,
+    triggered spurious callbacks and duplicate frees.
+    
+    This changes the logic to use a single variable "num_retired" to replace
+    both awaiting_reap and awaiting_discard.  num_retired is incremented
+    only in handle_bulk_completion() and thus there is no race.  The handler
+    will know that all URBs have been canceled when num_retired becomes
+    equal to num_urbs.
+    
+    This change also simplifies a great deal of the logic in both functions
+    and is a net reduction in the amount of code.
+    
+    Note that some variables such as "reap_action" probably need to still be
+    protected by a mutex, and this patch does not address that issue.
+    
+    Signed-off-by: David Moore <dcm@acm.org>
+
+commit 34b9eebe35d8167d43cffb6ad6175f6b2251b572
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Dec 13 20:06:49 2008 +0000
+
+    v1.0.0 release
+    
+    It's here!
+
+commit b1d636dde418dc8fe6a8f037dea0d800e57c6b94
+Author: Mikhail Gusarov <dottedmag@dottedmag.ent>
+Date:   Wed Dec 10 15:24:05 2008 +0600
+
+    EOL-whitespace fixes
+    
+    Signed-off-by: Mikhail Gusarov <dottedmag@dottedmag.ent>
+
+commit 4a9ac382ba5149ae5b3d0962d6a840b5e0dc13aa
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue Dec 9 21:43:37 2008 +0000
+
+    Linux: fix reading of active configuration
+    
+    Shannon Chuang pointed out that we only read 1 byte into an
+    uninitialized integer, and then return the whole thing.
+
+commit 81a7310d92461ba7b1d98aeff7c4c007fab07120
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue Dec 9 21:39:11 2008 +0000
+
+    Fix double free in descriptor parsing error path
+    
+    Pointed out by Shannon Chuang.
+
+commit 9b4b53453db56ba9c1d707a645bbe6c7a02a3c81
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Nov 21 13:28:32 2008 +0000
+
+    Improvements to multi-threaded I/O system
+    
+    Documentation brushed up, and I realised that another function is
+    needed for tight event handling loops -- they must be able to check
+    if an open/close operation is trying to interrupt it.
+
+commit 0e5b0fcb77a90b8bd95ad23669da472af31ef069
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Nov 21 11:00:47 2008 +0000
+
+    SourceForge website upload system changed
+
+commit a133875e6e2f52eff53ac03f505d59cbdd33e178
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Nov 21 10:54:57 2008 +0000
+
+    v0.9.4 release
+
+commit c32aa662769b676ff3247778664fccc71fc427ec
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu Nov 20 15:31:10 2008 +0000
+
+    Pause event handling while opening and closing devices
+    
+    Ludovic Rousseau found that crashes often occur if you close a device
+    while another thread is doing event handling.
+    
+    Fix this by adding an internal control pipe, which the close routines
+    use to interrupt the event handler and obtain the event handling lock,
+    ensuring that no other thread is handling events while the device is
+    closed. After the close completes, it signals all the event handlers
+    to start up again using the usual mechanism.
+    
+    Also modified libusb_open() to do a similar thing, so that event
+    handlers are interrupted in order to realise that a new poll fd has
+    appeared.
+
+commit 1d7cf3d0fa8698eae25097cbda1870be90ff6f5e
+Author: Bastien Nocera <hadess@hadess.net>
+Date:   Thu Oct 30 14:35:23 2008 +0000
+
+    Add libusb_attach_kernel_driver()
+    
+    Add support for re-attaching a driver to a device under Linux.
+    
+    [dsd: fixed handling of return value, and added LIBUSB_ERROR_BUSY case]
+
+commit 914a4e70657c86b5094770aa2d898c978b1cdf41
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Nov 2 21:45:54 2008 +0000
+
+    Linux: handle low-level transfer errors
+    
+    Handle more URB error status codes, thanks to Lou and Alan Stern.
+
+commit d25b566b3b8febafdda4211de724b4727dd4b7e0
+Author: Aurelien Jarno <aurelien@aurel32.net>
+Date:   Thu Sep 4 13:50:49 2008 +0200
+
+    Support for out-of-tree building
+    
+    Contrary to libusb 0.1, libusb 1.0 does not support out-of-tree building
+    for the documentation part. This patch fixes that by using a
+    doxygen.cfg.in file, which contains @top_srcdir@ to refer to the
+    location of the libusb source code.
+
+commit 8674c67ef78e1cf89db1fa584a4304f7c5ddcc5f
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Nov 2 15:00:39 2008 +0000
+
+    Document the logging style
+    
+    Suggested by Lou.
+
+commit 94936cbcfe3f02eb65c8b91e29896604316259d8
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Wed Aug 27 22:44:24 2008 -0500
+
+    Async I/O documentation touchups
+
+commit 2f8f1b1a900f5b9828e5e2ff93c2b26a44fd9de2
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Wed Aug 27 21:23:10 2008 -0500
+
+    Doc: fix typo in events lock section
+
+commit 046e681e4ac6b697e40458ee0f5baf3cd8763bb0
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Aug 23 01:00:21 2008 -0500
+
+    v0.9.3 release
+
+commit fec6eaa4eecdf7e0b8299157a5dabef94417f193
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Aug 23 00:57:44 2008 -0500
+
+    Reset internal transfer flags on submit
+    
+    This fixes a problem pointed out by Lou, where resubmitting a transfer
+    that previously timed out never timed out again, as if the timeout had
+    been set to 0.
+
+commit 81627bd38900ec9701ab69c141aa51a9abea1f60
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Aug 10 17:09:48 2008 -0500
+
+    Add libusb_get_configuration prototype
+    
+    Pointed out by Lou
+
+commit 1631eaefcc7cdf7047c6b9225618a9aa1b3d87d1
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Jul 19 17:51:28 2008 -0500
+
+    v0.9.2 release
+
+commit 0d9c40d7f3eee15ada624b5caab2cfb912144fdc
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Wed Jul 16 09:22:12 2008 -0500
+
+    Linux: fix sysfs directory handling
+    
+    The length of the directory name varies, e.g. when you have nested hubs.
+    Use dynamic allocation to be able to deal with any length of name.
+
+commit 66c9847ad54b126ccafd4877292454ab57d0c115
+Author: David Engraf <dogge2k@gmx.de>
+Date:   Wed Jul 16 09:16:38 2008 -0500
+
+    Linux: correct usage of MAX_PATH
+    
+    Thanks to clarification from Artem Egorkine, MAX_PATH already includes
+    space for the trailing NULL.
+
+commit 6494f07a6d1b73ce786ae581c4ff691e39e61d19
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue Jul 8 21:15:54 2008 -0500
+
+    Linux: fix bulk/iso transfer double-cancellation
+    
+    Reset counters to 0 so that it's possible to cancel a transfer twice
+    without breaking things. Not sure that I want to support this properly,
+    but this makes it work at least.
+
+commit 9140f5b414e37a3714cde9c6d6c87c963338a83a
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Jun 28 21:28:44 2008 -0500
+
+    v0.9.1 release
+
+commit 83a029062c1d2bfb584d7a6ee94915583d37464c
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Jun 28 21:24:49 2008 -0500
+
+    Add missing GET_CONTEXT()
+
+commit fbad9a5426f0369394c88987355a8fb06a741ca1
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Jun 28 21:18:41 2008 -0500
+
+    Linux: Compatibility with new sysfs descriptors file
+    
+    As of 2.6.26, the descriptors file now includes all descriptors, not
+    just the active one.
+
+commit 819e65f880ca43526036e56c65c415042c91f58f
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu Jun 26 22:47:05 2008 -0500
+
+    Allow user data pointer to be passed through pollfd notification API
+
+commit 1df713d622ab4f0b03aad72d903ac7beb8fb3b90
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue Jun 24 23:01:51 2008 -0500
+
+    Introduce contexts to the API
+    
+    Suggested by David Zeuthen. This allows multiple libraries in the same
+    process to independently use libusb without interfering.
+
+commit 9818151c60a85aea6af24cb0996a92c3726c9864
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue Jun 24 21:31:13 2008 -0500
+
+    Revert "Temporary workaround for event handling serialization issue"
+    
+    This reverts commit 2d3a1111caff40ebb87983c861ff548cdc9e5946.
+    This was based on the assumption that dying threads would automatically
+    release mutexes, which is not the case.
+
+commit d5f82893fab3f1c13b1af4ba17aac72479bad7d5
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Jun 20 23:04:53 2008 -0500
+
+    Overflow handling
+
+commit 546dee211eefbdd280fd1fc9dee84a9b52105078
+Author: Artem Egorkine <arteme@gmail.com>
+Date:   Tue Jun 17 18:27:38 2008 -0500
+
+    a fix for SIGSEGV in handle_bulk_completion()
+    
+    We cannot dereference tpriv after calling
+    usbi_handle_transfer_cancellation() because that function may invoke
+    the user-supplied callback which may free the transfer.
+
+commit 947ba8056456a5215724fb502e3e09d50016f699
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon Jun 16 22:50:50 2008 -0500
+
+    Refine configuration selection again
+    
+    At Alan Stern's suggestion, just offer the bare "set configuration" and
+    "get configuration" functionality, and let applications worry about the
+    specific race conditions and unusual situations.
+
+commit e7a7a49d0331ee0e14145f6e7ec39763b36314ac
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Jun 15 15:29:38 2008 -0500
+
+    docs update
+    
+    Add a THANKS file, make copyright notices easily accessible, update TODO
+
+commit 217534e4b396081e038ee5f94c813d1668963673
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Jun 15 15:23:29 2008 -0500
+
+    round up poll timeout
+    
+    Pointed out by Richard Röjfors, otherwise we end up busy-looping with
+    a poll() timeout of 0.
+
+commit 5ad79b324bc5e11a75a585398a1e81c26f05e758
+Author: Felipe Balbi <me@felipebalbi.com>
+Date:   Sun Jun 8 12:34:48 2008 +0300
+
+    fix doc about libusb_open()
+    
+    libusb_open() returns int instead of libusb_device_handle.
+    
+    Signed-off-by: Felipe Balbi <me@felipebalbi.com>
+    [dsd: small correction]
+
+commit 2d3a1111caff40ebb87983c861ff548cdc9e5946
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu May 29 17:26:26 2008 +0100
+
+    Temporary workaround for event handling serialization issue
+    
+    Ludovic Rousseau pointed out that libusb_unlock_events() is not called
+    when a thread gets terminated with a signal, meaning that event waiters
+    will not be woken up in this case.
+    
+    Add a temporary hack to libusb_event_handler_active() so that at least
+    the other threads will realise on the next iteration of their event
+    handling loop.
+    
+    The real fix will likely involve reworking most of this.
+
+commit 514bb8790cfe8b93ccfff82bc17081b1030acce0
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu May 29 12:35:01 2008 +0100
+
+    Refine libusb_set_configuration() semantics
+    
+    Applications will generally want to set a configuration before claiming
+    interfaces. The problem is that the interface may already be set, and
+    someone else may have claimed an interface (meaning that all calls to
+    set_configuration will fail, even if it's for the same configuration).
+    
+    There are now 2 options:
+    1. Use the new libusb_get_configuration() to determine active
+       configuration before calling libusb_set_configuration()
+    2. Or just call libusb_set_configuration() as usual, which will do
+       nothing if that configuration is already active.
+
+commit d1292f8e7300051239a7ed2769d221dc7a6f9fca
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun May 25 23:42:42 2008 +0100
+
+    v0.9.0 release
+    
+    First libusb-1.0 beta release
+
+commit 4cd249388e4ed2ca03f1263984ab67df5030bb65
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun May 25 22:59:09 2008 +0100
+
+    Take lock before raising event waiters condition
+    
+    This avoids a race between the user checking for active event handler
+    and then blocking on the condition variable
+
+commit 7c525480ab3c4db9205bfe30bb0d2bef9096c444
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 23 15:57:07 2008 +0100
+
+    Implement serialization of event handlers
+    
+    Now offers a mechanism to wait for events while another thread is
+    doing the event handling. Complicates things for MT async apps, but
+    then again it's a bit of a tricky combination to start with.
+
+commit ff0660a415ecfd0879600eaad1c5899b6d93a30a
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat May 24 21:28:31 2008 +0100
+
+    allow LIBUSB_DEBUG env var to control message verbosity at runtime
+    
+    Based on ideas from Ludovic Rousseau
+
+commit 4d788967e3f8d75eaf3a1ac1ee8e2e8bed0601c1
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 23 15:58:11 2008 +0100
+
+    don't print messages by default
+    
+    Add libusb_set_debug() API to set message verbosity.
+    
+    Ludovic Rousseau pointed out that applications may close stdout/stderr
+    descriptors, which might then be reused.
+
+commit bef33bb9eba0da04ee7488d9cd5e6ab12bc61c0c
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon May 19 15:43:27 2008 +0100
+
+    Fix memory leak in libusb_control_transfer
+    
+    Pointed out by David Engraf: we weren't freeing the transfer buffer
+
+commit a345bacb6f07ebb2122402041a9e8092d4a20a4d
+Author: David Engraf <david.engraf@netcom.eu>
+Date:   Mon May 19 15:16:32 2008 +0100
+
+    Linux: fix handling of ioctl failure
+    
+    The return value of some ioctl commands in linux_usbfs.c are not
+    handeled correct. The ioctl function returns != 0 and errno is set with
+    the error code.
+
+commit e44396a458ecea9e5edd9a7577e617571c76860d
+Author: David Engraf <david.engraf@netcom.eu>
+Date:   Mon May 19 15:13:38 2008 +0100
+
+    critical memory leak in handle_events
+    
+    This patch closes a critical memory leak in handle_events. The fds
+    variable is malloced but never freed. When I'm calling
+    handle_events with a timeout of 0, my system runs out of memory after a
+    few seconds.
+
+commit eb25630f52bc9848b444e439632c899977d887b0
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 16 23:50:20 2008 +0100
+
+    More informative libusb_open() return code
+    
+    Hopefully one of the last API tweaks...
+
+commit 2b2e9c40b195261b09ac52ebdb93eef25c79de90
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 16 22:37:56 2008 +0100
+
+    Fix endianness with descriptor handling
+    
+    Alan Stern pointed out that usbfs gives host-endian data, but sysfs gives
+    bus-endian.
+
+commit 1298c51f516a7bf04ca9add1b7db14417cdc66f3
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon May 12 18:46:37 2008 +0100
+
+    Backend documentation for porting efforts
+    
+    Hopefully comprehensive enough for people to get started.
+
+commit ade26afc42c34ceb1c45afcadd2ea5e8240eaca4
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon May 12 15:43:30 2008 +0100
+
+    Linux: fix caching of guessed configuration
+    
+    Reported and tested by Xiaofan Chen
+
+commit e25d590a9198995b4f0b6afeb41ecae318715e7e
+Author: Rob Walker <rob@tenfoot.org.uk>
+Date:   Sun May 11 21:14:18 2008 +0100
+
+    Linux: fix bulk transfer early completion
+    
+    We were forgetting about the remaining urbs when a non-final urb
+    completed early.
+    
+    [dsd: some touchups and a warning message for a corner case that we don't handle]
+
+commit fec7c84163e25b8f811632828334d75da82bcb16
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun May 11 20:31:58 2008 +0100
+
+    Handle hot-unplugging
+    
+    This involved moving from select() to poll() because there is no way to
+    distinguish usbfs's POLLERR condition with select().
+
+commit aeb905fa5d78cdbba80a680aa7a2bb7338f27f65
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun May 11 16:04:35 2008 +0100
+
+    Documentation work
+
+commit ba5d9a45c06311204f51faef41d1ee215bb5b823
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun May 11 15:36:24 2008 +0100
+
+    Endianness of control setup packets
+    
+    Document behaviour where host-endian and bus-endian (little) should be
+    used respectively.
+    
+    Also remove packed attribute from libusb_control_setup as all fields
+    are naturally aligned.
+
+commit 7bedc3b2683f35ee1dd39a2ebe0ec05be0019f38
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun May 11 15:11:59 2008 +0100
+
+    Document that releasing interface causes SET_INTERFACE control request
+
+commit f2ede9876cd4f5cfa7751b975670fa449187fe3d
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat May 10 21:45:42 2008 +0100
+
+    Support unconfigured devices
+
+commit 8ebb4ccdfaf5f095a1c38787d909d280ea64405c
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat May 10 20:56:44 2008 +0100
+
+    Linux: fix caching of active configuration for non-sysfs
+
+commit c3844f7aeb2176636ce6e6ef697659fdb0b30048
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat May 10 14:42:43 2008 +0100
+
+    Fetch configurations by index (not value)
+    
+    Otherwise there is no way to know which values to look for.
+
+commit d77052c0d630e33737c38d601fd633155f6b2229
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat May 10 00:12:53 2008 +0100
+
+    Linux: comprehensive sysfs vs usbfs access
+    
+    Be more flexible when certain parts of sysfs are not available.
+
+commit 74bc842bac1a32a26323da6c3e8af2f66e1b5cfa
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 9 19:38:13 2008 +0100
+
+    Linux: no need to store usbfs node path
+    
+    This can be computed from bus number and device address
+
+commit fe4adcc99e30115204ab832ad3e0170c9aca7629
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 9 14:34:31 2008 +0100
+
+    Rework configuration handling
+    
+    libusb no longer caches descriptors in libusb_device but backends are
+    intended to be able to provide copies from memory. In the common linux
+    case we can use sysfs.
+
+commit 5741bfe01a2481b8c3830c80edc3637bf62a7e16
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 9 14:36:14 2008 +0100
+
+    libusb_get_device_list() can return negative error code
+
+commit 45413101b78298e9332b22a34bc6bc159000ad8a
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu May 8 23:09:21 2008 +0100
+
+    Linux: fix clear_halt implementation
+    
+    The ioctl expects an integer.
+    Bug found with the assistance of Soumen Mondal
+
+commit 10d4e427cc171dfd6ad7f43a33ce3cfebcd7aa04
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu May 8 23:04:52 2008 +0100
+
+    Documentation work
+    
+    Partially based on some libusb-devel discussions
+
+commit ded0a249322571a075e3ed3528021864247dfa55
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon May 5 22:57:48 2008 +0100
+
+    Linux: enumerate devices and descriptors from sysfs
+    
+    Suggested by Alan Stern. This avoids waking up any suspended USB devices.
+    sysfs is not available on all systems, so the usbfs mechanism is still
+    in place as a fallback.
+
+commit 885c2a5de69d6b7d8902bb55d6d83680a5a1a6e5
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon May 5 21:34:31 2008 +0100
+
+    documentation touchups
+
+commit 59c205d542b43d79fe28622dbe8f03a3a3300b6f
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon May 5 21:17:03 2008 +0100
+
+    more error code sanitization
+
+commit 88055d4b5913102a90ff666f75fd922c74860dc5
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon May 5 20:57:43 2008 +0100
+
+    Isochronous transfer helper functions
+
+commit a95c943ed301dcd20e92b0b3b255568899a4c42e
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon May 5 17:54:33 2008 +0100
+
+    free open devices on exit
+
+commit b27fff633843824744df7d334cb89ece329cafa6
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon May 5 17:47:49 2008 +0100
+
+    move descriptor parsing into main library
+    
+    OS modules now provide functionality for fetching device/config
+    descriptors
+
+commit a304eca71f22c6df7d70a901483b30f1b8e93378
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon May 5 16:22:33 2008 +0100
+
+    Detect endpoint halts and unsupported control requests
+
+commit 7da521954ba661d3f537440c31a84b66e974d56b
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon May 5 01:00:31 2008 +0100
+
+    Linux: fix logical URB allocation
+    
+    We were allocating the wrong number of URBs for transfers of size
+    multiples of 16k.
+
+commit 470b1bc42bf53373ce678fc76bab9160a54d6881
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun May 4 16:51:23 2008 +0100
+
+    add functionality for querying and detaching kernel driver
+
+commit 17ecfb0ecc833596c43755c80d461cddb9b3b0d7
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun May 4 16:20:46 2008 +0100
+
+    Descriptor reading functionality
+
+commit bdce367d1bd8691465844b2411c85215498f517d
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun May 4 14:22:16 2008 +0100
+
+    sanitized error returns from synchronous I/O functions
+
+commit bfe74e9cd9c17a40fff042ea0647326f51cfecae
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun May 4 14:10:19 2008 +0100
+
+    implement libusb_reset_device()
+
+commit c01f744ce07bbeccbe353e956479f0cc5a811a6f
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun May 4 13:46:41 2008 +0100
+
+    Add functionality to clear endpoint halt conditions
+
+commit 5878daa85e3364bb3885190425d4f9deaa2d8c36
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun May 4 00:51:59 2008 +0100
+
+    Fix libusb_get_device_list return value
+    
+    It was documented to return the list length, but was returning 0.
+
+commit a74106a9b48b88bae0e099be34a18d653a8f1238
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat May 3 16:50:58 2008 +0100
+
+    Well-defined error codes for some operations
+    
+    Also renamed set_interface_altsetting to set_interface_alt_setting for
+    better consistency
+
+commit 0f463fe671455670efcf4a93e526b2a9082b0afe
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat May 3 16:24:11 2008 +0100
+
+    Add libusb_set_configuration()
+
+commit e65608994f795f97e4d6adac20329ca08709db2d
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat May 3 15:40:23 2008 +0100
+
+    rename LIBUSB_ERROR_NOMEM to LIBUSB_ERROR_NO_MEM
+    improves consistency
+
+commit 5384bbf300779e7936eac9ebd33ee38f5b533f8e
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat May 3 14:34:54 2008 +0100
+
+    Linux: better EACCES handling
+
+commit 1936eeeba3f933a078df1005cc7c1533a8ec2bac
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat May 3 14:26:56 2008 +0100
+
+    Rename reference counting API
+    
+    This improves consistency with the naming style of other functions
+
+commit e2f822b4f17342f614ab2455179a80975fca6cb0
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat May 3 14:24:40 2008 +0100
+
+    Linux: use read-only access to enumerate devices and descriptors
+    
+    Write access is not needed until later.
+    Also fix handling of open() error code.
+
+commit 81204eed3d0a7744b89b68bd90d567b68d191a91
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 2 17:45:23 2008 +0100
+
+    document pollfd notifiers
+
+commit e20f8281fb7da32587f81b5eea5818af1eab0fe0
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 2 17:33:52 2008 +0100
+
+    Allow multiple interfaces to be claimed
+
+commit 66685ff25d81a1f1a2a3dbda882d407638d00672
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 2 16:55:36 2008 +0100
+
+    Documentation improvements
+
+commit 55bce39cbe0c9746a428b66751d1afe551d86381
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 2 12:55:34 2008 +0100
+
+    detect short descriptor reads
+
+commit f3f17846dcced6b2dc40f899ed6a2aba151c264b
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 2 12:32:46 2008 +0100
+
+    remove "references" and "referenced by" listings in documentation
+
+commit fbb017dd9a26ce449578482b95157b3c850fa446
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 2 12:32:08 2008 +0100
+
+    Use typedef ptr types in parameters and return types
+    
+    This is passed through to the docs
+
+commit 3675e978fb7a1042f8601931255658bcd14a2298
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri May 2 12:28:31 2008 +0100
+
+    Expose bus number and device address
+
+commit 2012898ffc492317cb428d97077bf5ee0e98e1da
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue Apr 29 15:26:46 2008 +0100
+
+    standardised error codes
+
+commit 0269c75ae3de7acb2dc555e45928750e35fdb320
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue Apr 29 13:34:26 2008 +0100
+
+    Fix descriptor handling memory leaks
+
+commit d3ab4e3bd4068cba41c1e12c4b175018dc3cb343
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Apr 27 23:50:01 2008 +0100
+
+    Rename endpoint_type to transfer_type
+    
+    Matches the USB specs more closely
+
+commit 379e90e0fdcef6f4db1849fa0a7fd524407cf564
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Apr 27 23:41:24 2008 +0100
+
+    Remove a FIXME comment
+    
+    it can't.
+
+commit 2ddf81420557d016bbcbf28dda0d8d1c64d16264
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Apr 27 23:30:34 2008 +0100
+
+    Fix unlocked flying_transfers list access
+
+commit 7ac0a405b4c57db42e88cbcba5f135697f03b646
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Apr 27 23:27:04 2008 +0100
+
+    Remove libusb_cancel_transfer_sync
+    
+    This wasn't a particularly nice API. Cancellation should be handled by
+    the completion handler.
+
+commit a5006fd7b9dae6f1db7969c8744086ba3a7c027b
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Apr 27 19:56:02 2008 +0100
+
+    remove extra timeout check
+    
+    If select() didn't timeout then don't check for more timeouts
+
+commit 3bdafaa359d9c65e1af360b5338e1f25528a8066
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Apr 27 19:53:51 2008 +0100
+
+    Documentation touchups
+    
+    Detail that interrupt polling interval is fixed to endpoint bInterval,
+    and that data may be transferred even on a timeout condition.
+
+commit e12618c79d520955b1abf80a277e881d91907162
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Apr 19 16:17:53 2008 +0100
+
+    add threaded example program
+
+commit 1fcdb0678b759569db7cd530457dbc0a5f86fb1d
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Apr 18 23:58:54 2008 +0100
+
+    libusb_device mutex protection
+
+commit 0efd2efa65d5513e5754d717d522b2c5c45332e2
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Apr 18 23:42:40 2008 +0100
+
+    mutex protection for device and handle lists
+
+commit d2ff2b14a15e5099ff0214502944de30f141a39c
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Apr 18 20:00:31 2008 +0100
+
+    lock flying_transfers during transfer removal
+
+commit 2569980762cb66804da31e54bef243702da8dfe9
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Apr 18 19:59:56 2008 +0100
+
+    pollfds mutex protection
+
+commit f5a33e08ec0da51ccb5e95a5adec50c5211a9bf5
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu Apr 17 18:24:54 2008 +0100
+
+    flying_transfers mutex protection
+    
+    This marks the beginnings of thread safety
+
+commit 85e1994123545125ce0653415d122f9790f8d041
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu Apr 17 17:44:28 2008 +0100
+
+    Linux: fix control transfer cancellation
+
+commit cf9b831f7bfd97ba88721c1d934aeda522f3692c
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon Apr 14 20:03:27 2008 +0100
+
+    set correct endpoint type for isochronous transfers
+    
+    Pointed out by Felix Domke
+
+commit ad6e2b712c5b54af44424e58a2776686314e26b7
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Apr 11 21:40:07 2008 +0100
+
+    Linux: fire multiple URBs at once for split transfers
+    
+    This results in a significant performance increase for bulk transfers
+    larger than 16kb, and fixes a bug where data would be spliced and mixed
+    between two simultaneously submitted transfers to the same endpoint.
+    
+    It also allows isochronous transfers larger than 16kb to be submitted.
+    
+    This commit also improves cancellation - the library now understands
+    what is going on.
+
+commit d9b2ce2894ed43d34de6850f2dac50ccabf1db55
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue Apr 1 23:28:32 2008 +0100
+
+    Constify some return data
+    
+    Make it clear that apps should not mess with these structures
+
+commit 8d809854e2b19c2b7c27ab05e5d76b34e2a5cead
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Mar 30 22:19:00 2008 +0100
+
+    Rename libusb_poll() to libusb_handle_events()
+
+commit 211f80c9f2a4a58cd2bbf5b7751f45089c8961e7
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue Mar 25 16:24:30 2008 +0000
+
+    Isochronous endpoint I/O
+    
+    Due to variable-sized structures, this involved changing allocation
+    mechanism. All transfers must now be allocated and freed through
+    libusb.
+    
+    A synchronous function is missing, and I could do with writing a few
+    more helper functions to simplify things.
+
+commit b1ade6fca668d8aa156d5b5bf3a933f116144dc2
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Mar 23 21:17:32 2008 +0000
+
+    distcheck fix for docs
+
+commit 62077b7fa5b222e1bb9dea3467585aed69d596e2
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Mar 23 21:13:14 2008 +0000
+
+    Support for changing altsetting
+    
+    Will probably be suject to later consideration w.r.t. claiming of endpoints
+
+commit 0499e9f418607b5786ac0c3e97bc46737a609ca3
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu Mar 20 21:10:01 2008 +0000
+
+    it's called bmRequestType
+
+commit 88884ae4bbe721dac117d5190303cb67852fa5d3
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu Mar 20 21:07:00 2008 +0000
+
+    Save transfer flags before invoking callback
+    
+    The callback may free the transfer, in which case we can't read the flags
+    after it has returned.
+
+commit ead09cde6895df0034a685516987ce253575e9a7
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Mar 15 16:35:12 2008 +0000
+
+    API documentation
+    
+    Hopefully mostly complete. Some constants were renamed and move into
+    enums.
+
+commit 285724cc14ea5f993e2c4c92fe0aaf6c335bc139
+Author: Vasily Khoruzhick <anarsoul@gmail.com>
+Date:   Sat Mar 15 13:50:53 2008 +0200
+
+    Fix get_device_list for realloc case
+    
+    get_device_list can modify pointer passed to it with realloc, but this
+    case wasn't handled and caused crash on my machine. Fixed
+    
+    Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
+
+commit c0c9432d38b22784070dce3a7874c62c31786a27
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu Mar 13 12:36:56 2008 +0000
+
+    Beginnings of cross-platform abstraction
+    
+    This also includes a libusb_get_pollfds API change
+
+commit de4c5341d168697baa4c0901c406deb47e78aae7
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon Mar 10 18:38:15 2008 +0000
+
+    Add transfer flags
+
+commit aae05f688dc26a013166ab9436fd25018b49d76a
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon Mar 10 11:32:15 2008 +0000
+
+    Simplify libusb_fill_control_transfer()
+    
+    Transfer length can be inferred from the setup packet.
+
+commit 7c5ea95297c2f3f6afc42f60c1bf1bef777bb1fb
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon Mar 10 11:29:24 2008 +0000
+
+    get_device fixup
+    
+    Rename API away from "devh" and fix implementation to match header
+
+commit 9e89d1aa82cbe7e21672ee3e2e545238fffc5318
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Mar 9 16:27:06 2008 +0000
+
+    Rename descriptor-getting functions
+    
+    Based on feedback from Tim Roberts
+
+commit 283ae96c3ccbcee1c3950fce18ae47093ae8200e
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Mar 9 16:15:02 2008 +0000
+
+    Simplify cancellation API
+    
+    No need to provide the device here.
+
+commit ebad1c79688ba603ad017ed0fe2f3c0dc8edd1ad
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Mar 9 16:12:08 2008 +0000
+
+    Rename libusb_dev_handle to libusb_device_handle
+
+commit 1ac0a7d88f282b6f293c456fac8edb143cbaca3d
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Mar 9 01:01:57 2008 +0000
+
+    Move synchronous I/O implementation to its own file
+
+commit 66348c90ea4570bf999ac301089e006d0cce1926
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Mar 9 00:58:09 2008 +0000
+
+    Separate transfer allocation and submission
+    
+    Leads to some hefty API changes. Now we're much more similar to the
+    Linux kernel model.
+    
+    Problems with dealing with asynchronous control transfers are passed
+    on to the user, basically you must allocate a buffer, start with the
+    setup, and put the data after. This won't make much sense until
+    documented (soon...)
+
+commit d21ebe47ce578c93cd8969be1c933d503e32e5d4
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Mar 8 12:48:35 2008 +0000
+
+    Rework URB API naming
+    
+    Now refer to everything as "transfers" as consistent with the USB spec
+    libusb_transfer is now a kind of transfer handle. To reduce confusion
+    with libusb_bulk_transfer and libusb_control_transfer, those have been
+    renamed to libusb_{control,bulk}_transfer_request.
+
+commit fd6fb3cc093ad47271353a0e468d16547f991382
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Mar 8 11:53:33 2008 +0000
+
+    Add fallback on /proc/bus/usb
+    
+    /dev/bus/usb is a relatively new thing probably not present on every
+    system
+
+commit f3fdf447916289cd92b7190377681894e8ab611a
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Mar 8 00:10:16 2008 +0000
+
+    Persistent libusb_device storage
+    
+    Devices are now assigned a session ID (currently busnum:devaddr) which
+    is used to distinguish unique devices.
+    
+    Now multiple callers of libusb_get_device_list will get the same
+    libusb_device structure instances.
+
+commit 23f8fb8bafeeda93ce234cb40eb7219d2e36c19c
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu Mar 6 23:43:57 2008 +0000
+
+    Add convenience function to find and open a device by USB VID+PID
+    
+    Lots of libusb apps I write are simple test apps not intended to be real
+    apps. Having a function available to quickly locate my device will be
+    handy in such situations.
+
+commit 9cfdb494fccac53a4277da7c8b6d15f1a72a4959
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu Mar 6 23:25:20 2008 +0000
+
+    Rework device discovery API
+    
+    libusb_find_devices and libusb_get_devices are no more
+    
+    libusb_get_device_list obtains a list of libusb_device structures for all
+    known devices in the system.
+    
+    Each libusb_device now has a reference count, defaulting to 1 on
+    instantiation. The reference count of 1 refers to the fact that it is
+    present in the list in this scenario.
+    
+    Opening a device adds a pointer to the libusb_device structure in the
+    handle, so that also adds a reference. Closing the device removes that
+    reference.
+    
+    The function to free the device list can optionally unref all the devices
+    inside.
+    
+    In future we will make the libusb_device instances all "global" so that if
+    the app calls get_device_list twice it actually gets the same libusb_device
+    structure references back. This way we can start to track disconnects, and
+    we can investigate adding a unique "session ID" to each libusb_device, an
+    identifier guaranteed to be unique to that device until reboot.
+
+commit 77cea822788e024c848c7f554915f771a2dc1e0f
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Thu Mar 6 17:05:04 2008 +0000
+
+    Remove ctrl debug code
+    
+    This was unintentionally committed
+
+commit b873521a6f575628d535f89278bb67888004d0ca
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Tue Feb 26 22:11:34 2008 +0000
+
+    Notifications for changes to the fd set
+    
+    Applications can now be notified when they should start and stop polling
+    new file descriptors.
+
+commit ca66e16a370c828d08a5bc3f9f203db145c81a4c
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Feb 1 12:20:20 2008 +0000
+
+    Fix header installation path
+
+commit e583100a4086c411093eef5c450880b965df6b1b
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Wed Jan 30 13:24:54 2008 +0000
+
+    TODO update
+
+commit 637a8d7ff8a11a23588925d9d3003a609bda8075
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Wed Jan 30 13:19:10 2008 +0000
+
+    Remove timers and signalfd
+    
+    Instead of timers, add a mechanism for informing the parent app when the
+    next timeout is due to happen, so that it can call us at that time.
+    
+    As we no longer use signals, signalfd has also been removed.
+
+commit 8c56abe2e13ed4dd8c15737c21be7b6b1e5cf2ac
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Jan 26 18:16:56 2008 +0000
+
+    Poll usbfs descriptors directly
+    
+    We don't need to use signalfd for this functionality because we can poll
+    the file descriptors for write events.
+
+commit e3ce855acec33d37dd833bca5dad5e8c3773003a
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Jan 26 17:26:40 2008 +0000
+
+    Fix dpfp example compilation
+
+commit 1d41a5cda2fefe826877ee4445199af30aa188b7
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Jan 26 17:22:53 2008 +0000
+
+    C++ header safety
+    
+    Pointed out by JF
+
+commit 37b7f9a112eb1441d352467f661205b8872d0553
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Jan 26 14:03:43 2008 +0000
+
+    Only use -fgnu89-inline when supported
+    
+    J F pointed out that this option only works on gcc 4.3 and newer.
+
+commit e3a09ca0b9cb6f46d54a0130f678c6097240a2bd
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sat Jan 5 21:59:40 2008 +0000
+
+    Remove more fpusb remnants
+
+commit dcd5e0075fa84601d997d29bb60bc8370b97a375
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Jan 4 01:19:07 2008 +0000
+
+    TODO update
+    
+    Start listing the things I want to discuss/reconsider before 1.0 API
+    is final.
+
+commit de53d972ed9c1f21f86ffd585560520e986f212c
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Jan 4 01:17:06 2008 +0000
+
+    Rename some _devh_ functions
+    
+    Decided against naming functions in this style based on advice from
+    Tim Roberts. Still not really sure about devh naming in general.
+
+commit 132d84bf8ae34bd0892b3d8207a53d87cc0a9cba
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Jan 4 01:13:25 2008 +0000
+
+    Use "transfer" instead of "msg"
+    
+    Based on a discussion with Tim Roberts.
+
+commit ea6af58a8643137eb01eeb7d2f65404e390feb1b
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Jan 4 00:57:00 2008 +0000
+
+    Plural of bus is busses
+    
+    SF #1633043
+
+commit dbb3fd871e3972b4e670f3161e7cd2f58f357600
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Jan 4 00:54:57 2008 +0000
+
+    API renaming: remove fpi and usb_ stuff
+    
+    fpi changed to usbi.
+    
+    We should not expose structures with prefix "usb_" in the public
+    namespace as it is quite likely there will be some conflict somewhere.
+    Instead, using "libusb_" should be safer.
+
+commit e9364d72151ae1de9cce4175f330fe1529f02511
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Fri Jan 4 00:40:49 2008 +0000
+
+    Rename to libusb-1.0
+    
+    I've taken over the libusb project, and what was previously known as fpusb
+    will eventually be released as libusb-1.0.
+
+commit f4ed0b6a3e0a20555fdfc9e9b8be7e8a2c8ae192
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Dec 30 22:09:50 2007 +0000
+
+    Compiler flags update
+    
+    Also fix some warnings
+
+commit d3d671efe27491baf1d2ceadbfeeb4e7428d6f9a
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Dec 30 22:05:17 2007 +0000
+
+    Fix signalfd structure size on x86
+    
+    ptr is a 64-bit value
+
+commit dfac6756faad76071a92945e3e3a16b8a841a7ea
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Wed Dec 12 23:32:54 2007 +0000
+
+    Don't pass ctrl_msg/bulk_msg structures through async paths
+    
+    These are easiest to construct on the stack, but in the async case it is
+    likely that the submitting function returns (hence stack is destroyed)
+    before URB completion.
+
+commit a8d2881eb7c273892acf2ff6e1f3f552631d1d11
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon Dec 3 23:29:22 2007 +0000
+
+    Add functionality to access device descriptors
+
+commit b5a7a411087b37a6bf56b4688a9e3290daaed153
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Mon Dec 3 22:27:21 2007 +0000
+
+    Rename fpusb_device_handle functions to devh
+    
+    Prevents confusion with functions that work on fpusb_dev structures.
+
+commit eacf4505a473df0f521d1b69d5b45448f0709e2d
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Sun Dec 2 23:16:57 2007 +0000
+
+    Add API to access poll fd
+    
+    Almost forgot... :)
+
+commit 852bba4754ec57679c823f33e8feba6e4a564cbe
+Author: Daniel Drake <dsd@gentoo.org>
+Date:   Wed Nov 28 13:48:45 2007 +0000
+
+    Initial commit
+    
+    Basic library structure which supports enumerating detected USB devices

+ 28 - 0
compat/libusb-1.0/Makefile.am

@@ -0,0 +1,28 @@
+AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip
+ACLOCAL_AMFLAGS = -I m4
+DISTCLEANFILES = libusb-1.0.pc
+MAINTAINERCLEANFILES = ChangeLog
+EXTRA_DIST = TODO PORTING msvc
+SUBDIRS = libusb doc
+
+if BUILD_EXAMPLES
+SUBDIRS += examples
+endif
+
+pkgconfigdir=$(libdir)/pkgconfig
+pkgconfig_DATA=libusb-1.0.pc
+
+.PHONY: ChangeLog dist-up
+ChangeLog:
+	git --git-dir $(top_srcdir)/.git log > ChangeLog || touch ChangeLog
+
+dist-hook: ChangeLog
+
+reldir = .release/$(distdir)
+dist-up: dist
+	rm -rf $(reldir)
+	mkdir -p $(reldir)
+	cp $(distdir).tar.bz2 $(reldir)
+	rsync -rv $(reldir) frs.sourceforge.net:/home/frs/project/l/li/libusb/libusb-1.0/
+	rm -rf $(reldir)
+

+ 65 - 0
compat/libusb-1.0/NEWS

@@ -0,0 +1,65 @@
+This file lists notable changes in each release. For the full history of all
+changes, see ChangeLog.
+
+2012-04-20: 1.0.9
+* Numerous bug fixes and improvements
+* Backend for Windows, for devices using the WinUSB.sys driver
+* Backend for OpenBSD and NetBSD, for devices using the ugen driver
+* Add libusb_get_device_speed()
+* Add libusb_has_capability()
+* Add libusb_error_name()
+* Add libusb_get_version()
+
+2010-05-07: v1.0.8
+* Bug fixes
+
+2010-04-19: v1.0.7
+* Bug fixes and documentation tweaks
+* Add more interface class definitions
+
+2009-11-22: v1.0.6
+* Bug fixes
+* Increase libusb_handle_events() timeout to 60s for powersaving
+
+2009-11-15: v1.0.5
+ * Use timerfd when available for timer management
+ * Small fixes/updates
+
+2009-11-06: v1.0.4 release
+ * Bug fixes including transfer locking to fix some potential threading races
+ * More flexibility with clock types on Linux
+ * Use new bulk continuation tracking in Linux 2.6.32 for improved handling
+   of short/failed transfers
+
+2009-08-27: v1.0.3 release
+ * Bug fixes
+ * Add libusb_get_max_iso_packet_size()
+
+2009-06-13: v1.0.2 release
+ * Bug fixes
+
+2009-05-12: v1.0.1 release
+ * Bug fixes
+ * Darwin backend
+
+2008-12-13: v1.0.0 release
+ * Bug fixes
+
+2008-11-21: v0.9.4 release
+ * Bug fixes
+ * Add libusb_attach_kernel_driver()
+
+2008-08-23: v0.9.3 release
+ * Bug fixes
+
+2008-07-19: v0.9.2 release
+ * Bug fixes
+
+2008-06-28: v0.9.1 release
+ * Bug fixes
+ * Introduce contexts to the API
+ * Compatibility with new Linux kernel features
+
+2008-05-25: v0.9.0 release
+ * First libusb-1.0 beta release
+

+ 95 - 0
compat/libusb-1.0/PORTING

@@ -0,0 +1,95 @@
+PORTING LIBUSB TO OTHER PLATFORMS
+
+Introduction
+============
+
+This document is aimed at developers wishing to port libusb to unsupported
+platforms. I believe the libusb API is OS-independent, so by supporting
+multiple operating systems we pave the way for cross-platform USB device
+drivers.
+
+Implementation-wise, the basic idea is that you provide an interface to
+libusb's internal "backend" API, which performs the appropriate operations on
+your target platform.
+
+In terms of USB I/O, your backend provides functionality to submit
+asynchronous transfers (synchronous transfers are implemented in the higher
+layers, based on the async interface). Your backend must also provide
+functionality to cancel those transfers.
+
+Your backend must also provide an event handling function to "reap" ongoing
+transfers and process their results.
+
+The backend must also provide standard functions for other USB operations,
+e.g. setting configuration, obtaining descriptors, etc.
+
+
+File descriptors for I/O polling
+================================
+
+For libusb to work, your event handling function obviously needs to be called
+at various points in time. Your backend must provide a set of file descriptors
+which libusb and its users can pass to poll() or select() to determine when
+it is time to call the event handling function.
+
+On Linux, this is easy: the usbfs kernel interface exposes a file descriptor
+which can be passed to poll(). If something similar is not true for your
+platform, you can emulate this using an internal library thread to reap I/O as
+necessary, and a pipe() with the main library to raise events. The file
+descriptor of the pipe can then be provided to libusb as an event source.
+
+
+Interface semantics and documentation
+=====================================
+
+Documentation of the backend interface can be found in libusbi.h inside the
+usbi_os_backend structure definition.
+
+Your implementations of these functions will need to call various internal
+libusb functions, prefixed with "usbi_". Documentation for these functions
+can be found in the .c files where they are implemented.
+
+You probably want to skim over *all* the documentation before starting your
+implementation. For example, you probably need to allocate and store private
+OS-specific data for device handles, but the documentation for the mechanism
+for doing so is probably not the first thing you will see.
+
+The Linux backend acts as a good example - view it as a reference
+implementation which you should try to match the behaviour of.
+
+
+Getting started
+===============
+
+1. Modify configure.ac to detect your platform appropriately (see the OS_LINUX
+stuff for an example).
+
+2. Implement your backend in the libusb/os/ directory, modifying
+libusb/os/Makefile.am appropriately.
+
+3. Add preprocessor logic to the top of libusb/core.c to statically assign the
+right usbi_backend for your platform.
+
+4. Produce and test your implementation.
+
+5. Send your implementation to libusb-devel mailing list.
+
+
+Implementation difficulties? Questions?
+=======================================
+
+If you encounter difficulties porting libusb to your platform, please raise
+these issues on the libusb-devel mailing list. Where possible and sensible, I
+am interested in solving problems preventing libusb from operating on other
+platforms.
+
+The libusb-devel mailing list is also a good place to ask questions and
+make suggestions about the internal API. Hopefully we can produce some
+better documentation based on your questions and other input.
+
+You are encouraged to get involved in the process; if the library needs
+some infrastructure additions/modifications to better support your platform,
+you are encouraged to make such changes (in cleanly distinct patch
+submissions). Even if you do not make such changes yourself, please do raise
+the issues on the mailing list at the very minimum.
+

+ 22 - 0
compat/libusb-1.0/README

@@ -0,0 +1,22 @@
+libusb
+======
+
+libusb is a library for USB device access from Linux, Mac OS X,
+OpenBSD, NetBSD, and Windows userspace.
+It is written in C and licensed under the LGPL-2.1 (see COPYING).
+
+libusb is abstracted internally in such a way that it can hopefully
+be ported to other operating systems. See the PORTING file for some
+information, if you fancy a challenge. :)
+
+libusb homepage:
+http://libusb.org/
+
+Developers will wish to consult the API documentation:
+http://libusb.sourceforge.net/api-1.0/
+
+Use the mailing list for questions, comments, etc:
+http://libusb.org/wiki/MailingList
+
+- Peter Stuge <peter@stuge.se>
+(use the mailing list rather than mailing developers directly)

+ 8 - 0
compat/libusb-1.0/THANKS

@@ -0,0 +1,8 @@
+Development contributors are listed in the AUTHORS file. Other community
+members who have made significant contributions in other areas are listed
+in this file:
+
+Alan Stern
+Ludovic Rousseau
+Tim Roberts
+Xiaofan Chen

+ 9 - 0
compat/libusb-1.0/TODO

@@ -0,0 +1,9 @@
+for 1.1 or future
+==================
+optional timerfd support (runtime detection)
+notifications of hotplugged/unplugged devices
+offer API to create/destroy handle_events thread
+isochronous sync I/O?
+exposing of parent-child device relationships
+"usb primer" introduction docs
+more examples

+ 232 - 0
compat/libusb-1.0/configure.ac

@@ -0,0 +1,232 @@
+dnl These m4 macros are whitespace sensitive and break if moved around much.
+m4_define([LU_VERSION_H], m4_include([libusb/version.h]))
+m4_define([LU_DEFINE_VERSION_ATOM],
+	[m4_define([$1], m4_bregexp(LU_VERSION_H,
+	[^#define\s*$1\s*\([0-9]*\).*], [\1]))])
+m4_define([LU_DEFINE_VERSION_RC_ATOM],
+	[m4_define([$1], m4_bregexp(LU_VERSION_H,
+	[^#define\s*$1\s*"\(-rc[0-9]*\)".*], [\1]))])
+dnl The m4_bregexp() returns (only) the numbers following the #define named
+dnl in the first macro parameter. m4_define() then defines the name for use
+dnl in AC_INIT().
+
+LU_DEFINE_VERSION_ATOM([LIBUSB_MAJOR])
+LU_DEFINE_VERSION_ATOM([LIBUSB_MINOR])
+LU_DEFINE_VERSION_ATOM([LIBUSB_MICRO])
+LU_DEFINE_VERSION_RC_ATOM([LIBUSB_RC])
+
+AC_INIT([libusb], LIBUSB_MAJOR[.]LIBUSB_MINOR[.]LIBUSB_MICRO[]LIBUSB_RC, [libusb-devel@lists.sourceforge.net], [libusb], [http://www.libusb.org/])
+
+# Library versioning
+# These numbers should be tweaked on every release. Read carefully:
+# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
+# http://sourceware.org/autobook/autobook/autobook_91.html
+lt_current="2"
+lt_revision="0"
+lt_age="0"
+LTLDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age}"
+
+AM_INIT_AUTOMAKE
+AM_MAINTAINER_MODE
+
+AC_CONFIG_SRCDIR([libusb/core.c])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_HEADERS([config.h])
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
+
+AC_PREREQ([2.50])
+AC_PROG_CC
+AC_PROG_LIBTOOL
+LT_LANG([Windows Resource])
+AC_C_INLINE
+AM_PROG_CC_C_O
+AC_DEFINE([_GNU_SOURCE], 1, [Use GNU extensions])
+
+LTLDFLAGS="${LTLDFLAGS} -no-undefined"
+
+AC_MSG_CHECKING([operating system])
+case $host in
+*-linux*)
+	AC_MSG_RESULT([Linux])
+	backend="linux"
+	;;
+*-darwin*)
+	AC_MSG_RESULT([Darwin/Mac OS X])
+	backend="darwin"
+	;;
+*-openbsd*)
+	AC_MSG_RESULT([OpenBSD])
+	backend="openbsd"
+	;;
+*-netbsd*)
+	AC_MSG_RESULT([NetBSD (using OpenBSD backend)])
+	backend="openbsd"
+	;;
+*-mingw*)
+	AC_MSG_RESULT([Windows])
+	backend="windows"
+	;;
+*-cygwin*)
+	AC_MSG_RESULT([Cygwin (using Windows backend)])
+	backend="windows"
+	threads="posix"
+	;;
+*)
+	AC_MSG_ERROR([unsupported operating system])
+esac
+case $backend in
+linux)
+	AC_DEFINE(OS_LINUX, 1, [Linux backend])
+	AC_SUBST(OS_LINUX)
+	AC_CHECK_LIB(rt, clock_gettime, -pthread)
+	AC_ARG_ENABLE([udev],
+                      [AC_HELP_STRING([--with-udev], [use udev for device enumeration and hotplug support (recommended, default: yes)])],
+                      [], [enable_udev="yes"])
+        if test "x$enable_udev" = "xyes" ; then
+                # system has udev. use it or fail!
+                AC_CHECK_HEADERS([libudev.h],[],[AC_ERROR(["udev support requested but libudev not installed"])])
+                AC_CHECK_LIB([udev], [udev_new], [], [AC_ERROR(["udev support requested but libudev not installed"])])
+                AC_DEFINE(USE_UDEV, 1, [Use udev for device enumeration/hotplug])
+        else
+                AC_CHECK_HEADERS([linux/netlink.h linux/filter.h], [], [AC_ERROR(["Linux netlink headers not found"])])
+        fi
+        AC_SUBST(USE_UDEV)
+	threads="posix"
+	THREAD_CFLAGS="-pthread"
+	LIBS="${LIBS} -pthread"
+	AC_CHECK_HEADERS([poll.h])
+	AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
+	;;
+darwin)
+	AC_DEFINE(OS_DARWIN, 1, [Darwin backend])
+	AC_SUBST(OS_DARWIN)
+	threads="posix"
+	LIBS="-lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation"
+	LTLDFLAGS="${LTLDFLAGS} -Wl,-prebind"
+	AC_CHECK_HEADERS([poll.h])
+	AC_CHECK_TYPE([nfds_t],
+		[AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])],
+		[AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])],
+		[#include <poll.h>])
+	;;
+openbsd)
+	AC_DEFINE(OS_OPENBSD, 1, [OpenBSD backend])
+	AC_SUBST(OS_OPENBSD)
+	threads="posix"
+	THREAD_CFLAGS="-pthread"
+	LIBS="-pthread"
+	AC_CHECK_HEADERS([poll.h])
+	AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
+	;;
+windows)
+	AC_DEFINE(OS_WINDOWS, 1, [Windows backend])
+	AC_SUBST(OS_WINDOWS)
+	LIBS=""
+	LTLDFLAGS="${LTLDFLAGS} -avoid-version -Wl,--add-stdcall-alias"
+	AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])
+	;;
+esac
+AC_SUBST(LIBS)
+
+AM_CONDITIONAL(OS_LINUX, test "x$backend" = xlinux)
+AM_CONDITIONAL(OS_DARWIN, test "x$backend" = xdarwin)
+AM_CONDITIONAL(OS_OPENBSD, test "x$backend" = xopenbsd)
+AM_CONDITIONAL(OS_WINDOWS, test "x$backend" = xwindows)
+AM_CONDITIONAL(THREADS_POSIX, test "x$threads" = xposix)
+AM_CONDITIONAL(USE_UDEV, test "x$enable_udev" = xyes)
+if test "$threads" = posix; then
+	AC_DEFINE(THREADS_POSIX, 1, [Use POSIX Threads])
+fi
+
+# timerfd
+AC_CHECK_HEADER([sys/timerfd.h], [timerfd_h=1], [timerfd_h=0])
+AC_ARG_ENABLE([timerfd],
+	[AS_HELP_STRING([--enable-timerfd],
+		[use timerfd for timing (default auto)])],
+	[use_timerfd=$enableval], [use_timerfd='auto'])
+
+if test "x$use_timerfd" = "xyes" -a "x$timerfd_h" = "x0"; then
+	AC_MSG_ERROR([timerfd header not available; glibc 2.9+ required])
+fi
+
+AC_CHECK_DECL([TFD_NONBLOCK], [tfd_hdr_ok=yes], [tfd_hdr_ok=no], [#include <sys/timerfd.h>])
+if test "x$use_timerfd" = "xyes" -a "x$tfd_hdr_ok" = "xno"; then
+	AC_MSG_ERROR([timerfd header not usable; glibc 2.9+ required])
+fi
+
+AC_MSG_CHECKING([whether to use timerfd for timing])
+if test "x$use_timerfd" = "xno"; then
+	AC_MSG_RESULT([no (disabled by user)])
+else
+	if test "x$timerfd_h" = "x1" -a "x$tfd_hdr_ok" = "xyes"; then
+		AC_MSG_RESULT([yes])
+		AC_DEFINE(USBI_TIMERFD_AVAILABLE, 1, [timerfd headers available])
+	else
+		AC_MSG_RESULT([no (header not available)])
+	fi
+fi
+
+AC_CHECK_TYPES(struct timespec)
+
+# Message logging
+AC_ARG_ENABLE([log], [AS_HELP_STRING([--disable-log], [disable all logging])],
+	[log_enabled=$enableval],
+	[log_enabled='yes'])
+if test "x$log_enabled" != "xno"; then
+	AC_DEFINE([ENABLE_LOGGING], 1, [Message logging])
+fi
+
+AC_ARG_ENABLE([debug-log], [AS_HELP_STRING([--enable-debug-log],
+	[enable debug logging (default n)])],
+	[debug_log_enabled=$enableval],
+	[debug_log_enabled='no'])
+if test "x$debug_log_enabled" != "xno"; then
+	AC_DEFINE([ENABLE_DEBUG_LOGGING], 1, [Debug message logging])
+fi
+
+# Examples build
+AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build],
+	[build example applications (default n)])],
+	[build_examples=$enableval],
+	[build_examples='no'])
+AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != "xno"])
+
+# check for -fvisibility=hidden compiler support (GCC >= 3.4)
+saved_cflags="$CFLAGS"
+# -Werror required for cygwin
+CFLAGS="$CFLAGS -Werror -fvisibility=hidden"
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
+	[VISIBILITY_CFLAGS="-fvisibility=hidden"
+	 AC_DEFINE([DEFAULT_VISIBILITY], [__attribute__((visibility("default")))], [Default visibility]) ],
+	[ VISIBILITY_CFLAGS=""
+	 AC_DEFINE([DEFAULT_VISIBILITY], [], [Default visibility]) ],
+	])
+CFLAGS="$saved_cflags"
+
+# check for -Wno-pointer-sign compiler support (GCC >= 4)
+saved_cflags="$CFLAGS"
+CFLAGS="$CFLAGS -Wno-pointer-sign"
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
+	nopointersign_cflags="-Wno-pointer-sign", nopointersign_cflags="")
+CFLAGS="$saved_cflags"
+
+# sigaction not available on MinGW
+AC_CHECK_FUNC([sigaction], [have_sigaction=yes], [have_sigaction=no])
+AM_CONDITIONAL([HAVE_SIGACTION], [test "x$have_sigaction" = "xyes"])
+
+# headers not available on all platforms but required on others
+AC_CHECK_HEADERS([sys/time.h])
+AC_CHECK_FUNCS(gettimeofday)
+
+AM_CFLAGS="-std=gnu99 -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow ${THREAD_CFLAGS} ${VISIBILITY_CFLAGS}"
+
+AC_SUBST(AM_CFLAGS)
+AC_SUBST(LTLDFLAGS)
+
+AC_CONFIG_FILES([libusb-1.0.pc])
+AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([libusb/Makefile])
+AC_CONFIG_FILES([examples/Makefile])
+AC_CONFIG_FILES([doc/Makefile])
+AC_CONFIG_FILES([doc/doxygen.cfg])
+AC_OUTPUT

+ 10 - 0
compat/libusb-1.0/doc/Makefile.am

@@ -0,0 +1,10 @@
+EXTRA_DIST = doxygen.cfg.in
+
+docs: doxygen.cfg
+	doxygen $^
+
+docs-upload: docs
+	ln -s html api-1.0
+	rsync -av api-1.0/ web.sourceforge.net:htdocs/api-1.0/
+	rm -f api-1.0
+

+ 1294 - 0
compat/libusb-1.0/doc/doxygen.cfg.in

@@ -0,0 +1,1294 @@
+# Doxyfile 1.5.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file that 
+# follow. The default is UTF-8 which is also the encoding used for all text before 
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into 
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of 
+# possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = libusb
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = 
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, 
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, 
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, 
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to 
+# include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be extracted 
+# and appear in the documentation as a namespace called 'anonymous_namespace{file}', 
+# where file will be replaced with the base name of the file that contains the anonymous 
+# namespace. By default anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = NO
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from the 
+# version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = @top_srcdir@/libusb
+
+# This tag can be used to specify the character encoding of the source files that 
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default 
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. 
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = @top_srcdir@/libusb/libusbi.h @top_srcdir@/libusb/hotplug.h
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = 
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the output. 
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, 
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH 
+# then you must also enable this option. If you don't then doxygen will produce 
+# a warning and turn it on anyway
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.  Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = API_EXPORTED= LIBUSB_CALL= DEFAULT_VISIBILITY=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to 
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to 
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to 
+# be found in the default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will 
+# generate a caller dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable caller graphs for selected 
+# functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the number 
+# of direct children of the root node in a graph is already larger than 
+# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, which results in a white background. 
+# Warning: Depending on the platform used, enabling this option may lead to 
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to 
+# read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO

+ 15 - 0
compat/libusb-1.0/examples/Makefile.am

@@ -0,0 +1,15 @@
+AM_CPPFLAGS = -I$(top_srcdir)/libusb
+LDADD = ../libusb/libusb-1.0.la
+noinst_PROGRAMS = listdevs hotplugtest testlibusb1
+
+if HAVE_SIGACTION
+noinst_PROGRAMS += dpfp
+
+if THREADS_POSIX
+dpfp_threaded_CFLAGS = $(AM_CFLAGS)
+noinst_PROGRAMS += dpfp_threaded
+endif
+
+sam3u_benchmark_SOURCES = sam3u_benchmark.c
+noinst_PROGRAMS += sam3u_benchmark
+endif

+ 507 - 0
compat/libusb-1.0/examples/dpfp.c

@@ -0,0 +1,507 @@
+/*
+ * libusb example program to manipulate U.are.U 4000B fingerprint scanner.
+ * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ *
+ * Basic image capture program only, does not consider the powerup quirks or
+ * the fact that image encryption may be enabled. Not expected to work
+ * flawlessly all of the time.
+ *
+ * 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 <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <libusb.h>
+
+#define EP_INTR			(1 | LIBUSB_ENDPOINT_IN)
+#define EP_DATA			(2 | LIBUSB_ENDPOINT_IN)
+#define CTRL_IN			(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
+#define CTRL_OUT		(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)
+#define USB_RQ			0x04
+#define INTR_LENGTH		64
+
+enum {
+	MODE_INIT = 0x00,
+	MODE_AWAIT_FINGER_ON = 0x10,
+	MODE_AWAIT_FINGER_OFF = 0x12,
+	MODE_CAPTURE = 0x20,
+	MODE_SHUT_UP = 0x30,
+	MODE_READY = 0x80,
+};
+
+static int next_state(void);
+
+enum {
+	STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1,
+	STATE_AWAIT_IRQ_FINGER_DETECTED,
+	STATE_AWAIT_MODE_CHANGE_CAPTURE,
+	STATE_AWAIT_IMAGE,
+	STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF,
+	STATE_AWAIT_IRQ_FINGER_REMOVED,
+};
+
+static int state = 0;
+static struct libusb_device_handle *devh = NULL;
+static unsigned char imgbuf[0x1b340];
+static unsigned char irqbuf[INTR_LENGTH];
+static struct libusb_transfer *img_transfer = NULL;
+static struct libusb_transfer *irq_transfer = NULL;
+static int img_idx = 0;
+static int do_exit = 0;
+
+static int find_dpfp_device(void)
+{
+	devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a);
+	return devh ? 0 : -EIO;
+}
+
+static int print_f0_data(void)
+{
+	unsigned char data[0x10];
+	int r;
+	unsigned int i;
+
+	r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data,
+		sizeof(data), 0);
+	if (r < 0) {
+		fprintf(stderr, "F0 error %d\n", r);
+		return r;
+	}
+	if ((unsigned int) r < sizeof(data)) {
+		fprintf(stderr, "short read (%d)\n", r);
+		return -1;
+	}
+
+	printf("F0 data:");
+	for (i = 0; i < sizeof(data); i++)
+		printf("%02x ", data[i]);
+	printf("\n");
+	return 0;
+}
+
+static int get_hwstat(unsigned char *status)
+{
+	int r;
+
+	r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0);
+	if (r < 0) {
+		fprintf(stderr, "read hwstat error %d\n", r);
+		return r;
+	}
+	if ((unsigned int) r < 1) {
+		fprintf(stderr, "short read (%d)\n", r);
+		return -1;
+	}
+
+	printf("hwstat reads %02x\n", *status);
+	return 0;
+}
+
+static int set_hwstat(unsigned char data)
+{
+	int r;
+
+	printf("set hwstat to %02x\n", data);
+	r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0);
+	if (r < 0) {
+		fprintf(stderr, "set hwstat error %d\n", r);
+		return r;
+	}
+	if ((unsigned int) r < 1) {
+		fprintf(stderr, "short write (%d)", r);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int set_mode(unsigned char data)
+{
+	int r;
+	printf("set mode %02x\n", data);
+
+	r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0);
+	if (r < 0) {
+		fprintf(stderr, "set mode error %d\n", r);
+		return r;
+	}
+	if ((unsigned int) r < 1) {
+		fprintf(stderr, "short write (%d)", r);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer)
+{
+	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+		fprintf(stderr, "mode change transfer not completed!\n");
+		do_exit = 2;
+	}
+
+	printf("async cb_mode_changed length=%d actual_length=%d\n",
+		transfer->length, transfer->actual_length);
+	if (next_state() < 0)
+		do_exit = 2;
+}
+
+static int set_mode_async(unsigned char data)
+{
+	unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
+	struct libusb_transfer *transfer;
+
+	if (!buf)
+		return -ENOMEM;
+
+	transfer = libusb_alloc_transfer(0);
+	if (!transfer) {
+		free(buf);
+		return -ENOMEM;
+	}
+
+	printf("async set mode %02x\n", data);
+	libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1);
+	buf[LIBUSB_CONTROL_SETUP_SIZE] = data;
+	libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL,
+		1000);
+
+	transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK
+		| LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
+	return libusb_submit_transfer(transfer);
+}
+
+static int do_sync_intr(unsigned char *data)
+{
+	int r;
+	int transferred;
+
+	r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH,
+		&transferred, 1000);
+	if (r < 0) {
+		fprintf(stderr, "intr error %d\n", r);
+		return r;
+	}
+	if (transferred < INTR_LENGTH) {
+		fprintf(stderr, "short read (%d)\n", r);
+		return -1;
+	}
+
+	printf("recv interrupt %04x\n", *((uint16_t *) data));
+	return 0;
+}
+
+static int sync_intr(unsigned char type)
+{
+	int r;
+	unsigned char data[INTR_LENGTH];
+
+	while (1) {
+		r = do_sync_intr(data);
+		if (r < 0)
+			return r;
+		if (data[0] == type)
+			return 0;
+	}
+}
+
+static int save_to_file(unsigned char *data)
+{
+	FILE *fd;
+	char filename[64];
+
+	snprintf(filename, sizeof(filename), "finger%d.pgm", img_idx++);
+	fd = fopen(filename, "w");
+	if (!fd)
+		return -1;
+
+	fputs("P5 384 289 255 ", fd);
+	(void) fwrite(data + 64, 1, 384*289, fd);
+	fclose(fd);
+	printf("saved image to %s\n", filename);
+	return 0;
+}
+
+static int next_state(void)
+{
+	int r = 0;
+	printf("old state: %d\n", state);
+	switch (state) {
+	case STATE_AWAIT_IRQ_FINGER_REMOVED:
+		state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON;
+		r = set_mode_async(MODE_AWAIT_FINGER_ON);
+		break;
+	case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON:
+		state = STATE_AWAIT_IRQ_FINGER_DETECTED;
+		break;
+	case STATE_AWAIT_IRQ_FINGER_DETECTED:
+		state = STATE_AWAIT_MODE_CHANGE_CAPTURE;
+		r = set_mode_async(MODE_CAPTURE);
+		break;
+	case STATE_AWAIT_MODE_CHANGE_CAPTURE:
+		state = STATE_AWAIT_IMAGE;
+		break;
+	case STATE_AWAIT_IMAGE:
+		state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF;
+		r = set_mode_async(MODE_AWAIT_FINGER_OFF);
+		break;
+	case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF:
+		state = STATE_AWAIT_IRQ_FINGER_REMOVED;
+		break;
+	default:
+		printf("unrecognised state %d\n", state);
+	}
+	if (r < 0) {
+		fprintf(stderr, "error detected changing state\n");
+		return r;
+	}
+
+	printf("new state: %d\n", state);
+	return 0;
+}
+
+static void LIBUSB_CALL cb_irq(struct libusb_transfer *transfer)
+{
+	unsigned char irqtype = transfer->buffer[0];
+
+	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+		fprintf(stderr, "irq transfer status %d?\n", transfer->status);
+		do_exit = 2;
+		libusb_free_transfer(transfer);
+		irq_transfer = NULL;
+		return;
+	}
+
+	printf("IRQ callback %02x\n", irqtype);
+	switch (state) {
+	case STATE_AWAIT_IRQ_FINGER_DETECTED:
+		if (irqtype == 0x01) {
+			if (next_state() < 0) {
+				do_exit = 2;
+				return;
+			}
+		} else {
+			printf("finger-on-sensor detected in wrong state!\n");
+		}
+		break;
+	case STATE_AWAIT_IRQ_FINGER_REMOVED:
+		if (irqtype == 0x02) {
+			if (next_state() < 0) {
+				do_exit = 2;
+				return;
+			}
+		} else {
+			printf("finger-on-sensor detected in wrong state!\n");
+		}
+		break;
+	}
+	if (libusb_submit_transfer(irq_transfer) < 0)
+		do_exit = 2;
+}
+
+static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer)
+{
+	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+		fprintf(stderr, "img transfer status %d?\n", transfer->status);
+		do_exit = 2;
+		libusb_free_transfer(transfer);
+		img_transfer = NULL;
+		return;
+	}
+
+	printf("Image callback\n");
+	save_to_file(imgbuf);
+	if (next_state() < 0) {
+		do_exit = 2;
+		return;
+	}
+	if (libusb_submit_transfer(img_transfer) < 0)
+		do_exit = 2;
+}
+
+static int init_capture(void)
+{
+	int r;
+
+	r = libusb_submit_transfer(irq_transfer);
+	if (r < 0)
+		return r;
+
+	r = libusb_submit_transfer(img_transfer);
+	if (r < 0) {
+		libusb_cancel_transfer(irq_transfer);
+		while (irq_transfer)
+			if (libusb_handle_events(NULL) < 0)
+				break;
+		return r;
+	}
+
+	/* start state machine */
+	state = STATE_AWAIT_IRQ_FINGER_REMOVED;
+	return next_state();
+}
+
+static int do_init(void)
+{
+	unsigned char status;
+	int r;
+
+	r = get_hwstat(&status);
+	if (r < 0)
+		return r;
+
+	if (!(status & 0x80)) {
+		r = set_hwstat(status | 0x80);
+		if (r < 0)
+			return r;
+		r = get_hwstat(&status);
+		if (r < 0)
+			return r;
+	}
+
+	status &= ~0x80;
+	r = set_hwstat(status);
+	if (r < 0)
+		return r;
+
+	r = get_hwstat(&status);
+	if (r < 0)
+		return r;
+
+	r = sync_intr(0x56);
+	if (r < 0)
+		return r;
+
+	return 0;
+}
+
+static int alloc_transfers(void)
+{
+	img_transfer = libusb_alloc_transfer(0);
+	if (!img_transfer)
+		return -ENOMEM;
+
+	irq_transfer = libusb_alloc_transfer(0);
+	if (!irq_transfer)
+		return -ENOMEM;
+
+	libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf,
+		sizeof(imgbuf), cb_img, NULL, 0);
+	libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf,
+		sizeof(irqbuf), cb_irq, NULL, 0);
+
+	return 0;
+}
+
+static void sighandler(int signum)
+{
+	do_exit = 1;
+}
+
+int main(void)
+{
+	struct sigaction sigact;
+	int r = 1;
+
+	r = libusb_init(NULL);
+	if (r < 0) {
+		fprintf(stderr, "failed to initialise libusb\n");
+		exit(1);
+	}
+
+	r = find_dpfp_device();
+	if (r < 0) {
+		fprintf(stderr, "Could not find/open device\n");
+		goto out;
+	}
+
+	r = libusb_claim_interface(devh, 0);
+	if (r < 0) {
+		fprintf(stderr, "usb_claim_interface error %d\n", r);
+		goto out;
+	}
+	printf("claimed interface\n");
+
+	r = print_f0_data();
+	if (r < 0)
+		goto out_release;
+
+	r = do_init();
+	if (r < 0)
+		goto out_deinit;
+
+	/* async from here onwards */
+
+	r = alloc_transfers();
+	if (r < 0)
+		goto out_deinit;
+
+	r = init_capture();
+	if (r < 0)
+		goto out_deinit;
+
+	sigact.sa_handler = sighandler;
+	sigemptyset(&sigact.sa_mask);
+	sigact.sa_flags = 0;
+	sigaction(SIGINT, &sigact, NULL);
+	sigaction(SIGTERM, &sigact, NULL);
+	sigaction(SIGQUIT, &sigact, NULL);
+
+	while (!do_exit) {
+		r = libusb_handle_events(NULL);
+		if (r < 0)
+			goto out_deinit;
+	}
+
+	printf("shutting down...\n");
+
+	if (irq_transfer) {
+		r = libusb_cancel_transfer(irq_transfer);
+		if (r < 0)
+			goto out_deinit;
+	}
+
+	if (img_transfer) {
+		r = libusb_cancel_transfer(img_transfer);
+		if (r < 0)
+			goto out_deinit;
+	}
+
+	while (irq_transfer || img_transfer)
+		if (libusb_handle_events(NULL) < 0)
+			break;
+
+	if (do_exit == 1)
+		r = 0;
+	else
+		r = 1;
+
+out_deinit:
+	libusb_free_transfer(img_transfer);
+	libusb_free_transfer(irq_transfer);
+	set_mode(0);
+	set_hwstat(0x80);
+out_release:
+	libusb_release_interface(devh, 0);
+out:
+	libusb_close(devh);
+	libusb_exit(NULL);
+	return r >= 0 ? r : -r;
+}
+

+ 545 - 0
compat/libusb-1.0/examples/dpfp_threaded.c

@@ -0,0 +1,545 @@
+/*
+ * libusb example program to manipulate U.are.U 4000B fingerprint scanner.
+ * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ *
+ * Basic image capture program only, does not consider the powerup quirks or
+ * the fact that image encryption may be enabled. Not expected to work
+ * flawlessly all of the time.
+ *
+ * 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 <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <libusb.h>
+
+#define EP_INTR			(1 | LIBUSB_ENDPOINT_IN)
+#define EP_DATA			(2 | LIBUSB_ENDPOINT_IN)
+#define CTRL_IN			(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
+#define CTRL_OUT		(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)
+#define USB_RQ			0x04
+#define INTR_LENGTH		64
+
+enum {
+	MODE_INIT = 0x00,
+	MODE_AWAIT_FINGER_ON = 0x10,
+	MODE_AWAIT_FINGER_OFF = 0x12,
+	MODE_CAPTURE = 0x20,
+	MODE_SHUT_UP = 0x30,
+	MODE_READY = 0x80,
+};
+
+static int next_state(void);
+
+enum {
+	STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1,
+	STATE_AWAIT_IRQ_FINGER_DETECTED,
+	STATE_AWAIT_MODE_CHANGE_CAPTURE,
+	STATE_AWAIT_IMAGE,
+	STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF,
+	STATE_AWAIT_IRQ_FINGER_REMOVED,
+};
+
+static int state = 0;
+static struct libusb_device_handle *devh = NULL;
+static unsigned char imgbuf[0x1b340];
+static unsigned char irqbuf[INTR_LENGTH];
+static struct libusb_transfer *img_transfer = NULL;
+static struct libusb_transfer *irq_transfer = NULL;
+static int img_idx = 0;
+static int do_exit = 0;
+
+static pthread_t poll_thread;
+static pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t exit_cond_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static void request_exit(int code)
+{
+	do_exit = code;
+	pthread_cond_signal(&exit_cond);
+}
+
+static void *poll_thread_main(void *arg)
+{
+	int r = 0;
+	printf("poll thread running\n");
+
+	while (!do_exit) {
+		struct timeval tv = { 1, 0 };
+		r = libusb_handle_events_timeout(NULL, &tv);
+		if (r < 0) {
+			request_exit(2);
+			break;
+		}
+	}
+
+	printf("poll thread shutting down\n");
+	return NULL;
+}
+
+static int find_dpfp_device(void)
+{
+	devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a);
+	return devh ? 0 : -EIO;
+}
+
+static int print_f0_data(void)
+{
+	unsigned char data[0x10];
+	int r;
+	unsigned int i;
+
+	r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data,
+		sizeof(data), 0);
+	if (r < 0) {
+		fprintf(stderr, "F0 error %d\n", r);
+		return r;
+	}
+	if ((unsigned int) r < sizeof(data)) {
+		fprintf(stderr, "short read (%d)\n", r);
+		return -1;
+	}
+
+	printf("F0 data:");
+	for (i = 0; i < sizeof(data); i++)
+		printf("%02x ", data[i]);
+	printf("\n");
+	return 0;
+}
+
+static int get_hwstat(unsigned char *status)
+{
+	int r;
+
+	r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0);
+	if (r < 0) {
+		fprintf(stderr, "read hwstat error %d\n", r);
+		return r;
+	}
+	if ((unsigned int) r < 1) {
+		fprintf(stderr, "short read (%d)\n", r);
+		return -1;
+	}
+
+	printf("hwstat reads %02x\n", *status);
+	return 0;
+}
+
+static int set_hwstat(unsigned char data)
+{
+	int r;
+
+	printf("set hwstat to %02x\n", data);
+	r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0);
+	if (r < 0) {
+		fprintf(stderr, "set hwstat error %d\n", r);
+		return r;
+	}
+	if ((unsigned int) r < 1) {
+		fprintf(stderr, "short write (%d)", r);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int set_mode(unsigned char data)
+{
+	int r;
+	printf("set mode %02x\n", data);
+
+	r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0);
+	if (r < 0) {
+		fprintf(stderr, "set mode error %d\n", r);
+		return r;
+	}
+	if ((unsigned int) r < 1) {
+		fprintf(stderr, "short write (%d)", r);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer)
+{
+	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+		fprintf(stderr, "mode change transfer not completed!\n");
+		request_exit(2);
+	}
+
+	printf("async cb_mode_changed length=%d actual_length=%d\n",
+		transfer->length, transfer->actual_length);
+	if (next_state() < 0)
+		request_exit(2);
+}
+
+static int set_mode_async(unsigned char data)
+{
+	unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
+	struct libusb_transfer *transfer;
+
+	if (!buf)
+		return -ENOMEM;
+
+	transfer = libusb_alloc_transfer(0);
+	if (!transfer) {
+		free(buf);
+		return -ENOMEM;
+	}
+
+	printf("async set mode %02x\n", data);
+	libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1);
+	buf[LIBUSB_CONTROL_SETUP_SIZE] = data;
+	libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL,
+		1000);
+
+	transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK
+		| LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
+	return libusb_submit_transfer(transfer);
+}
+
+static int do_sync_intr(unsigned char *data)
+{
+	int r;
+	int transferred;
+
+	r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH,
+		&transferred, 1000);
+	if (r < 0) {
+		fprintf(stderr, "intr error %d\n", r);
+		return r;
+	}
+	if (transferred < INTR_LENGTH) {
+		fprintf(stderr, "short read (%d)\n", r);
+		return -1;
+	}
+
+	printf("recv interrupt %04x\n", *((uint16_t *) data));
+	return 0;
+}
+
+static int sync_intr(unsigned char type)
+{
+	int r;
+	unsigned char data[INTR_LENGTH];
+
+	while (1) {
+		r = do_sync_intr(data);
+		if (r < 0)
+			return r;
+		if (data[0] == type)
+			return 0;
+	}
+}
+
+static int save_to_file(unsigned char *data)
+{
+	FILE *fd;
+	char filename[64];
+
+	snprintf(filename, sizeof(filename), "finger%d.pgm", img_idx++);
+	fd = fopen(filename, "w");
+	if (!fd)
+		return -1;
+
+	fputs("P5 384 289 255 ", fd);
+	(void) fwrite(data + 64, 1, 384*289, fd);
+	fclose(fd);
+	printf("saved image to %s\n", filename);
+	return 0;
+}
+
+static int next_state(void)
+{
+	int r = 0;
+	printf("old state: %d\n", state);
+	switch (state) {
+	case STATE_AWAIT_IRQ_FINGER_REMOVED:
+		state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON;
+		r = set_mode_async(MODE_AWAIT_FINGER_ON);
+		break;
+	case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON:
+		state = STATE_AWAIT_IRQ_FINGER_DETECTED;
+		break;
+	case STATE_AWAIT_IRQ_FINGER_DETECTED:
+		state = STATE_AWAIT_MODE_CHANGE_CAPTURE;
+		r = set_mode_async(MODE_CAPTURE);
+		break;
+	case STATE_AWAIT_MODE_CHANGE_CAPTURE:
+		state = STATE_AWAIT_IMAGE;
+		break;
+	case STATE_AWAIT_IMAGE:
+		state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF;
+		r = set_mode_async(MODE_AWAIT_FINGER_OFF);
+		break;
+	case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF:
+		state = STATE_AWAIT_IRQ_FINGER_REMOVED;
+		break;
+	default:
+		printf("unrecognised state %d\n", state);
+	}
+	if (r < 0) {
+		fprintf(stderr, "error detected changing state\n");
+		return r;
+	}
+
+	printf("new state: %d\n", state);
+	return 0;
+}
+
+static void LIBUSB_CALL cb_irq(struct libusb_transfer *transfer)
+{
+	unsigned char irqtype = transfer->buffer[0];
+
+	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+		fprintf(stderr, "irq transfer status %d?\n", transfer->status);
+		irq_transfer = NULL;
+		request_exit(2);
+		return;
+	}
+
+	printf("IRQ callback %02x\n", irqtype);
+	switch (state) {
+	case STATE_AWAIT_IRQ_FINGER_DETECTED:
+		if (irqtype == 0x01) {
+			if (next_state() < 0) {
+				request_exit(2);
+				return;
+			}
+		} else {
+			printf("finger-on-sensor detected in wrong state!\n");
+		}
+		break;
+	case STATE_AWAIT_IRQ_FINGER_REMOVED:
+		if (irqtype == 0x02) {
+			if (next_state() < 0) {
+				request_exit(2);
+				return;
+			}
+		} else {
+			printf("finger-on-sensor detected in wrong state!\n");
+		}
+		break;
+	}
+	if (libusb_submit_transfer(irq_transfer) < 0)
+		request_exit(2);
+}
+
+static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer)
+{
+	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+		fprintf(stderr, "img transfer status %d?\n", transfer->status);
+		img_transfer = NULL;
+		request_exit(2);
+		return;
+	}
+
+	printf("Image callback\n");
+	save_to_file(imgbuf);
+	if (next_state() < 0) {
+		request_exit(2);
+		return;
+	}
+	if (libusb_submit_transfer(img_transfer) < 0)
+		request_exit(2);
+}
+
+static int init_capture(void)
+{
+	int r;
+
+	r = libusb_submit_transfer(irq_transfer);
+	if (r < 0)
+		return r;
+
+	r = libusb_submit_transfer(img_transfer);
+	if (r < 0) {
+		libusb_cancel_transfer(irq_transfer);
+		while (irq_transfer)
+			if (libusb_handle_events(NULL) < 0)
+				break;
+		return r;
+	}
+
+	/* start state machine */
+	state = STATE_AWAIT_IRQ_FINGER_REMOVED;
+	return next_state();
+}
+
+static int do_init(void)
+{
+	unsigned char status;
+	int r;
+
+	r = get_hwstat(&status);
+	if (r < 0)
+		return r;
+
+	if (!(status & 0x80)) {
+		r = set_hwstat(status | 0x80);
+		if (r < 0)
+			return r;
+		r = get_hwstat(&status);
+		if (r < 0)
+			return r;
+	}
+
+	status &= ~0x80;
+	r = set_hwstat(status);
+	if (r < 0)
+		return r;
+
+	r = get_hwstat(&status);
+	if (r < 0)
+		return r;
+
+	r = sync_intr(0x56);
+	if (r < 0)
+		return r;
+
+	return 0;
+}
+
+static int alloc_transfers(void)
+{
+	img_transfer = libusb_alloc_transfer(0);
+	if (!img_transfer)
+		return -ENOMEM;
+
+	irq_transfer = libusb_alloc_transfer(0);
+	if (!irq_transfer)
+		return -ENOMEM;
+
+	libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf,
+		sizeof(imgbuf), cb_img, NULL, 0);
+	libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf,
+		sizeof(irqbuf), cb_irq, NULL, 0);
+
+	return 0;
+}
+
+static void sighandler(int signum)
+{
+	request_exit(1);
+}
+
+int main(void)
+{
+	struct sigaction sigact;
+	int r = 1;
+
+	r = libusb_init(NULL);
+	if (r < 0) {
+		fprintf(stderr, "failed to initialise libusb\n");
+		exit(1);
+	}
+
+	r = find_dpfp_device();
+	if (r < 0) {
+		fprintf(stderr, "Could not find/open device\n");
+		goto out;
+	}
+
+	r = libusb_claim_interface(devh, 0);
+	if (r < 0) {
+		fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r));
+		goto out;
+	}
+	printf("claimed interface\n");
+
+	r = print_f0_data();
+	if (r < 0)
+		goto out_release;
+
+	r = do_init();
+	if (r < 0)
+		goto out_deinit;
+
+	/* async from here onwards */
+
+	sigact.sa_handler = sighandler;
+	sigemptyset(&sigact.sa_mask);
+	sigact.sa_flags = 0;
+	sigaction(SIGINT, &sigact, NULL);
+	sigaction(SIGTERM, &sigact, NULL);
+	sigaction(SIGQUIT, &sigact, NULL);
+
+	r = pthread_create(&poll_thread, NULL, poll_thread_main, NULL);
+	if (r)
+		goto out_deinit;
+
+	r = alloc_transfers();
+	if (r < 0) {
+		request_exit(1);
+		pthread_join(poll_thread, NULL);
+		goto out_deinit;
+	}
+
+	r = init_capture();
+	if (r < 0) {
+		request_exit(1);
+		pthread_join(poll_thread, NULL);
+		goto out_deinit;
+	}
+
+	while (!do_exit) {
+		pthread_mutex_lock(&exit_cond_lock);
+		pthread_cond_wait(&exit_cond, &exit_cond_lock);
+		pthread_mutex_unlock(&exit_cond_lock);
+	}
+
+	printf("shutting down...\n");
+	pthread_join(poll_thread, NULL);
+
+	r = libusb_cancel_transfer(irq_transfer);
+	if (r < 0) {
+		request_exit(1);
+		goto out_deinit;
+	}
+
+	r = libusb_cancel_transfer(img_transfer);
+	if (r < 0) {
+		request_exit(1);
+		goto out_deinit;
+	}
+
+	while (img_transfer || irq_transfer)
+		if (libusb_handle_events(NULL) < 0)
+			break;
+
+	if (do_exit == 1)
+		r = 0;
+	else
+		r = 1;
+
+out_deinit:
+	libusb_free_transfer(img_transfer);
+	libusb_free_transfer(irq_transfer);
+	set_mode(0);
+	set_hwstat(0x80);
+out_release:
+	libusb_release_interface(devh, 0);
+out:
+	libusb_close(devh);
+	libusb_exit(NULL);
+	return r >= 0 ? r : -r;
+}
+

+ 95 - 0
compat/libusb-1.0/examples/hotplugtest.c

@@ -0,0 +1,95 @@
+/*
+ * libusb example program for hotplug API
+ * Copyright (C) 2012-2013 Nathan Hjelm <hjelmn@mac.ccom>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <sched.h>
+#include <unistd.h>
+
+#include <libusb.h>
+
+int done = 0;
+libusb_device_handle *handle;
+
+static int hotplug_callback (libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data) {
+  struct libusb_device_descriptor desc;
+  int rc;
+
+  rc = libusb_get_device_descriptor(dev, &desc);
+  if (LIBUSB_SUCCESS != rc) {
+    fprintf (stderr, "Error getting device descriptor\n");
+  }
+
+  printf ("Device attach: %04x:%04x\n", desc.idVendor, desc.idProduct);
+
+  libusb_open (dev, &handle);
+
+  done++;
+
+  return 0;
+}
+
+static int hotplug_callback_detach (libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data) {
+  printf ("Device detached\n");
+
+  libusb_close (handle);
+
+  done++;
+  return 0;
+}
+
+int main (int argc, char *argv[]) {
+  libusb_hotplug_callback_handle hp[2];
+  int product_id, vendor_id, class_id;
+  int rc;
+
+  vendor_id  = (argc > 1) ? strtol (argv[1], NULL, 0) : 0x045a;
+  product_id = (argc > 2) ? strtol (argv[2], NULL, 0) : 0x5005;
+  class_id   = (argc > 3) ? strtol (argv[3], NULL, 0) : LIBUSB_HOTPLUG_MATCH_ANY;
+
+  libusb_init (NULL);
+
+  if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) {
+    printf ("Hotplug not supported by this build of libusb\n");
+    libusb_exit (NULL);
+    return EXIT_FAILURE;
+  }
+
+  rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0, vendor_id,
+                                         product_id, class_id, hotplug_callback, NULL, &hp[0]);
+  if (LIBUSB_SUCCESS != rc) {
+    fprintf (stderr, "Error registering callback 0\n");
+    libusb_exit (NULL);
+    return EXIT_FAILURE;
+  }
+
+  rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, vendor_id,
+                                         product_id,class_id, hotplug_callback_detach, NULL, &hp[1]);
+  if (LIBUSB_SUCCESS != rc) {
+    fprintf (stderr, "Error registering callback 1\n");
+    libusb_exit (NULL);
+    return EXIT_FAILURE;
+  }
+
+  while (done < 2) {
+    libusb_handle_events (NULL);
+  }
+
+  libusb_exit (NULL);
+}

+ 64 - 0
compat/libusb-1.0/examples/listdevs.c

@@ -0,0 +1,64 @@
+/*
+ * libusb example program to list devices on the bus
+ * Copyright (C) 2007 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 <stdio.h>
+#include <sys/types.h>
+
+#include <libusb.h>
+
+static void print_devs(libusb_device **devs)
+{
+	libusb_device *dev;
+	int i = 0;
+
+	while ((dev = devs[i++]) != NULL) {
+		struct libusb_device_descriptor desc;
+		int r = libusb_get_device_descriptor(dev, &desc);
+		if (r < 0) {
+			fprintf(stderr, "failed to get device descriptor");
+			return;
+		}
+
+		printf("%04x:%04x (bus %d, device %d)\n",
+			desc.idVendor, desc.idProduct,
+			libusb_get_bus_number(dev), libusb_get_device_address(dev));
+	}
+}
+
+int main(void)
+{
+	libusb_device **devs;
+	int r;
+	ssize_t cnt;
+
+	r = libusb_init(NULL);
+	if (r < 0)
+		return r;
+
+	cnt = libusb_get_device_list(NULL, &devs);
+	if (cnt < 0)
+		return (int) cnt;
+
+	print_devs(devs);
+	libusb_free_device_list(devs, 1);
+
+	libusb_exit(NULL);
+	return 0;
+}
+

+ 193 - 0
compat/libusb-1.0/examples/sam3u_benchmark.c

@@ -0,0 +1,193 @@
+/*
+ * libusb example program to measure Atmel SAM3U isochronous performance
+ * Copyright (C) 2012 Harald Welte <laforge@gnumonks.org>
+ *
+ * Copied with the author's permission under LGPL-2.1 from
+ * http://git.gnumonks.org/cgi-bin/gitweb.cgi?p=sam3u-tests.git;a=blob;f=usb-benchmark-project/host/benchmark.c;h=74959f7ee88f1597286cd435f312a8ff52c56b7e
+ *
+ * An Atmel SAM3U test firmware is also available in the above repository.
+ *
+ * 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 <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <libusb.h>
+
+
+#define EP_DATA_IN	0x82
+#define EP_ISO_IN	0x86
+
+static int do_exit = 0;
+static struct libusb_device_handle *devh = NULL;
+
+static unsigned long num_bytes = 0, num_xfer = 0;
+static struct timeval tv_start;
+
+static void cb_xfr(struct libusb_transfer *xfr)
+{
+	unsigned int i;
+
+	if (xfr->status != LIBUSB_TRANSFER_COMPLETED) {
+		fprintf(stderr, "transfer status %d\n", xfr->status);
+		libusb_free_transfer(xfr);
+		exit(3);
+	}
+
+	if (xfr->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
+		for (i = 0; i < xfr->num_iso_packets; i++) {
+			struct libusb_iso_packet_descriptor *pack = &xfr->iso_packet_desc[i];
+
+			if (pack->status != LIBUSB_TRANSFER_COMPLETED) {
+				fprintf(stderr, "Error: pack %u status %d\n", i, pack->status);
+				exit(5);
+			}
+
+			printf("pack%u length:%u, actual_length:%u\n", i, pack->length, pack->actual_length);
+		}
+	}
+
+	printf("length:%u, actual_length:%u\n", xfr->length, xfr->actual_length);
+	for (i = 0; i < xfr->actual_length; i++) {
+		printf("%02x", xfr->buffer[i]);
+		if (i % 16)
+			printf("\n");
+		else if (i % 8)
+			printf("  ");
+		else
+			printf(" ");
+	}
+	num_bytes += xfr->actual_length;
+	num_xfer++;
+
+	if (libusb_submit_transfer(xfr) < 0) {
+		fprintf(stderr, "error re-submitting URB\n");
+		exit(1);
+	}
+}
+
+static int benchmark_in(uint8_t ep)
+{
+	static uint8_t buf[2048];
+	static struct libusb_transfer *xfr;
+	int num_iso_pack = 0;
+
+	if (ep == EP_ISO_IN)
+		num_iso_pack = 16;
+
+	xfr = libusb_alloc_transfer(num_iso_pack);
+	if (!xfr)
+		return -ENOMEM;
+
+	if (ep == EP_ISO_IN) {
+		libusb_fill_iso_transfer(xfr, devh, ep, buf,
+				sizeof(buf), num_iso_pack, cb_xfr, NULL, 0);
+		libusb_set_iso_packet_lengths(xfr, sizeof(buf)/num_iso_pack);
+	} else
+		libusb_fill_bulk_transfer(xfr, devh, ep, buf,
+				sizeof(buf), cb_xfr, NULL, 0);
+
+	gettimeofday(&tv_start, NULL);
+
+	/* NOTE: To reach maximum possible performance the program must
+	 * submit *multiple* transfers here, not just one.
+	 *
+	 * When only one transfer is submitted there is a gap in the bus
+	 * schedule from when the transfer completes until a new transfer
+	 * is submitted by the callback. This causes some jitter for
+	 * isochronous transfers and loss of throughput for bulk transfers.
+	 *
+	 * This is avoided by queueing multiple transfers in advance, so
+	 * that the host controller is always kept busy, and will schedule
+	 * more transfers on the bus while the callback is running for
+	 * transfers which have completed on the bus.
+	 */
+
+	return libusb_submit_transfer(xfr);
+}
+
+static void measure(void)
+{
+	struct timeval tv_stop;
+	unsigned int diff_msec;
+
+	gettimeofday(&tv_stop, NULL);
+
+	diff_msec = (tv_stop.tv_sec - tv_start.tv_sec)*1000;
+	diff_msec += (tv_stop.tv_usec - tv_start.tv_usec)/1000;
+
+	printf("%lu transfers (total %lu bytes) in %u miliseconds => %lu bytes/sec\n",
+		num_xfer, num_bytes, diff_msec, (num_bytes*1000)/diff_msec);
+}
+
+static void sig_hdlr(int signum)
+{
+	switch (signum) {
+	case SIGINT:
+		measure();
+		do_exit = 1;
+		break;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int rc;
+	struct sigaction sigact;
+
+	sigact.sa_handler = sig_hdlr;
+	sigemptyset(&sigact.sa_mask);
+	sigact.sa_flags = 0;
+	sigaction(SIGINT, &sigact, NULL);
+
+	rc = libusb_init(NULL);
+	if (rc < 0) {
+		fprintf(stderr, "Error initializing libusb: %s\n", libusb_error_name(rc));
+		exit(1);
+	}
+
+	devh = libusb_open_device_with_vid_pid(NULL, 0x16c0, 0x0763);
+	if (!devh) {
+		fprintf(stderr, "Error finding USB device\n");
+		goto out;
+	}
+
+	rc = libusb_claim_interface(devh, 2);
+	if (rc < 0) {
+		fprintf(stderr, "Error claiming interface: %s\n", libusb_error_name(rc));
+		goto out;
+	}
+
+	benchmark_in(EP_ISO_IN);
+
+	while (!do_exit) {
+		rc = libusb_handle_events(NULL);
+		if (rc != LIBUSB_SUCCESS)
+			break;
+	}
+
+	/* Measurement has already been done by the signal handler. */
+
+	libusb_release_interface(devh, 0);
+out:
+	if (devh)
+		libusb_close(devh);
+	libusb_exit(NULL);
+	return rc;
+}

+ 256 - 0
compat/libusb-1.0/examples/testlibusb1.c

@@ -0,0 +1,256 @@
+/*
+ * Test suite program based of libusb-0.1-compat testlibusb
+ * Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.ccom>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <libusb.h>
+
+int verbose = 0;
+
+static void print_endpoint_comp(const struct libusb_ss_endpoint_companion_descriptor *ep_comp)
+{
+  printf("      USB 3.0 Endpoint Companion:\n");
+  printf("        bMaxBurst:        %d\n", ep_comp->bMaxBurst);
+  printf("        bmAttributes:     0x%02x\n", ep_comp->bmAttributes);
+  printf("        wBytesPerInterval: %d\n", ep_comp->wBytesPerInterval);
+}
+
+static void print_endpoint(const struct libusb_endpoint_descriptor *endpoint)
+{
+  int i, ret;
+
+  printf("      Endpoint:\n");
+  printf("        bEndpointAddress: %02xh\n", endpoint->bEndpointAddress);
+  printf("        bmAttributes:     %02xh\n", endpoint->bmAttributes);
+  printf("        wMaxPacketSize:   %d\n", endpoint->wMaxPacketSize);
+  printf("        bInterval:        %d\n", endpoint->bInterval);
+  printf("        bRefresh:         %d\n", endpoint->bRefresh);
+  printf("        bSynchAddress:    %d\n", endpoint->bSynchAddress);
+
+  for (i = 0 ; i < endpoint->extra_length ; ) {
+    if (LIBUSB_DT_SS_ENDPOINT_COMPANION == endpoint->extra[i+1]) {
+      struct libusb_ss_endpoint_companion_descriptor *ep_comp;
+
+      ret = libusb_parse_ss_endpoint_comp(endpoint->extra+i, endpoint->extra[0], &ep_comp);
+      if (LIBUSB_SUCCESS != ret) {
+        continue;
+      }
+
+      print_endpoint_comp(ep_comp);
+
+      libusb_free_ss_endpoint_comp(ep_comp);
+    }
+
+    i += endpoint->extra[i];
+  }
+}
+
+static void print_altsetting(const struct libusb_interface_descriptor *interface)
+{
+  int i;
+
+  printf("    Interface:\n");
+  printf("      bInterfaceNumber:   %d\n", interface->bInterfaceNumber);
+  printf("      bAlternateSetting:  %d\n", interface->bAlternateSetting);
+  printf("      bNumEndpoints:      %d\n", interface->bNumEndpoints);
+  printf("      bInterfaceClass:    %d\n", interface->bInterfaceClass);
+  printf("      bInterfaceSubClass: %d\n", interface->bInterfaceSubClass);
+  printf("      bInterfaceProtocol: %d\n", interface->bInterfaceProtocol);
+  printf("      iInterface:         %d\n", interface->iInterface);
+
+  for (i = 0; i < interface->bNumEndpoints; i++)
+    print_endpoint(&interface->endpoint[i]);
+}
+
+static void print_2_0_ext_cap(struct libusb_usb_2_0_device_capability_descriptor *usb_2_0_ext_cap)
+{
+  printf("    USB 2.0 Extension Capabilities:\n");
+  printf("      bDevCapabilityType: %d\n", usb_2_0_ext_cap->bDevCapabilityType);
+  printf("      bmAttributes:       0x%x\n", usb_2_0_ext_cap->bmAttributes);
+}
+
+static void print_ss_usb_cap(struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap)
+{
+  printf("    USB 3.0 Capabilities:\n");
+  printf("      bDevCapabilityType: %d\n", ss_usb_cap->bDevCapabilityType);
+  printf("      bmAttributes:       0x%x\n", ss_usb_cap->bmAttributes);
+  printf("      wSpeedSupported:    0x%x\n", ss_usb_cap->wSpeedSupported);
+  printf("      bFunctionalitySupport: %d\n", ss_usb_cap->bFunctionalitySupport);
+  printf("      bU1devExitLat:      %d\n", ss_usb_cap->bU1DevExitLat);
+  printf("      bU2devExitLat:      %d\n", ss_usb_cap->bU2DevExitLat);
+}
+
+static void print_bos(libusb_device_handle *handle)
+{
+  unsigned char buffer[128];
+  struct libusb_bos_descriptor *bos;
+  int ret;
+
+  ret = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, buffer, 128);
+  if (0 > ret) {
+    return;
+  }
+
+  ret = libusb_parse_bos_descriptor(buffer, 128, &bos);
+  if (0 > ret) {
+    return;
+  }
+
+  printf("  Binary Object Store (BOS):\n");
+  printf("    wTotalLength:       %d\n", bos->wTotalLength);
+  printf("    bNumDeviceCaps:     %d\n", bos->bNumDeviceCaps);
+  if (bos->usb_2_0_ext_cap) {
+    print_2_0_ext_cap(bos->usb_2_0_ext_cap);
+  }
+
+  if (bos->ss_usb_cap) {
+    print_ss_usb_cap(bos->ss_usb_cap);
+  }
+}
+
+static void print_interface(const struct libusb_interface *interface)
+{
+  int i;
+
+  for (i = 0; i < interface->num_altsetting; i++)
+    print_altsetting(&interface->altsetting[i]);
+}
+
+static void print_configuration(struct libusb_config_descriptor *config)
+{
+  int i;
+
+  printf("  Configuration:\n");
+  printf("    wTotalLength:         %d\n", config->wTotalLength);
+  printf("    bNumInterfaces:       %d\n", config->bNumInterfaces);
+  printf("    bConfigurationValue:  %d\n", config->bConfigurationValue);
+  printf("    iConfiguration:       %d\n", config->iConfiguration);
+  printf("    bmAttributes:         %02xh\n", config->bmAttributes);
+  printf("    MaxPower:             %d\n", config->MaxPower);
+
+  for (i = 0; i < config->bNumInterfaces; i++)
+    print_interface(&config->interface[i]);
+}
+
+static int print_device(libusb_device *dev, int level)
+{
+  struct libusb_device_descriptor desc;
+  libusb_device_handle *handle = NULL;
+  char description[256];
+  char string[256];
+  int ret, i;
+
+  ret = libusb_get_device_descriptor(dev, &desc);
+  if (ret < 0) {
+    fprintf(stderr, "failed to get device descriptor");
+    return -1;
+  }
+
+  ret = libusb_open(dev, &handle);
+  if (LIBUSB_SUCCESS == ret) {
+    if (desc.iManufacturer) {
+      ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string));
+      if (ret > 0)
+        snprintf(description, sizeof(description), "%s - ", string);
+      else
+        snprintf(description, sizeof(description), "%04X - ",
+                 desc.idVendor);
+    } else
+      snprintf(description, sizeof(description), "%04X - ",
+               desc.idVendor);
+
+    if (desc.iProduct) {
+      ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string));
+      if (ret > 0)
+        snprintf(description + strlen(description), sizeof(description) -
+                 strlen(description), "%s", string);
+      else
+        snprintf(description + strlen(description), sizeof(description) -
+                 strlen(description), "%04X", desc.idProduct);
+    } else
+      snprintf(description + strlen(description), sizeof(description) -
+               strlen(description), "%04X", desc.idProduct);
+  } else {
+    snprintf(description, sizeof(description), "%04X - %04X",
+             desc.idVendor, desc.idProduct);
+  }
+
+  printf("%.*sDev (bus %d, device %d): %s\n", level * 2, "                    ",
+         libusb_get_bus_number(dev), libusb_get_device_address(dev), description);
+
+  if (handle && verbose) {
+    if (desc.iSerialNumber) {
+      ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string));
+      if (ret > 0)
+        printf("%.*s  - Serial Number: %s\n", level * 2,
+               "                    ", string);
+    }
+  }
+
+  if (verbose) {
+    for (i = 0; i < desc.bNumConfigurations; i++) {
+      struct libusb_config_descriptor *config;
+      ret = libusb_get_config_descriptor(dev, i, &config);
+      if (LIBUSB_SUCCESS != ret) {
+        printf("  Couldn't retrieve descriptors\n");
+        continue;
+      }
+
+      print_configuration(config);
+
+      libusb_free_config_descriptor(config);
+    }
+
+    if (handle && desc.bcdUSB >= 0x0201) {
+      print_bos(handle);
+    }
+  }
+
+  if (handle)
+    libusb_close(handle);
+
+  return 0;
+}
+
+int main(int argc, char *argv[])
+{
+  libusb_device **devs;
+  ssize_t cnt;
+  int r, i;
+
+  if (argc > 1 && !strcmp(argv[1], "-v"))
+    verbose = 1;
+
+  r = libusb_init(NULL);
+  if (r < 0)
+    return r;
+
+  cnt = libusb_get_device_list(NULL, &devs);
+  if (cnt < 0)
+    return (int) cnt;
+
+  for (i = 0 ; devs[i] ; ++i) {
+    print_device(devs[i], 0);
+  }
+
+  libusb_free_device_list(devs, 1);
+
+  libusb_exit(NULL);
+  return 0;
+}

+ 12 - 0
compat/libusb-1.0/libusb-1.0.pc.in

@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libusb-1.0
+Description: C API for USB device access from Linux, Mac OS X, OpenBSD, NetBSD and Windows userspace
+Version: @VERSION@
+Libs: -L${libdir} -lusb-1.0
+Libs.private: @LIBS@
+Cflags: -I${includedir}/libusb-1.0
+

+ 55 - 0
compat/libusb-1.0/libusb/Makefile.am

@@ -0,0 +1,55 @@
+lib_LTLIBRARIES = libusb-1.0.la
+
+LINUX_USBFS_SRC = os/linux_usbfs.c
+DARWIN_USB_SRC = os/darwin_usb.c
+OPENBSD_USB_SRC = os/openbsd_usb.c
+WINDOWS_USB_SRC = os/poll_windows.c os/windows_usb.c libusb-1.0.rc \
+	libusb-1.0.def
+
+EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(OPENBSD_USB_SRC) \
+	$(WINDOWS_USB_SRC) os/threads_posix.c os/threads_windows.c \
+	os/linux_udev.c os/linux_netlink.c
+
+if OS_LINUX
+
+if USE_UDEV
+OS_SRC = $(LINUX_USBFS_SRC) os/linux_udev.c
+else
+OS_SRC = $(LINUX_USBFS_SRC) os/linux_netlink.c
+endif
+
+endif
+
+if OS_DARWIN
+OS_SRC = $(DARWIN_USB_SRC)
+AM_CFLAGS_EXT = -no-cpp-precomp
+endif
+
+if OS_OPENBSD
+OS_SRC = $(OPENBSD_USB_SRC)
+endif
+
+if OS_WINDOWS
+OS_SRC = $(WINDOWS_USB_SRC)
+
+.rc.lo:
+	$(AM_V_GEN)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@
+
+libusb-1.0.rc: version.h
+endif
+
+if THREADS_POSIX
+THREADS_SRC = os/threads_posix.h os/threads_posix.c
+else
+THREADS_SRC = os/threads_windows.h os/threads_windows.c
+endif
+
+libusb_1_0_la_CFLAGS = $(AM_CFLAGS) \
+	-DLIBUSB_DESCRIBE=\"`git --git-dir "$(top_srcdir)/.git" describe --tags 2>/dev/null`\"
+libusb_1_0_la_LDFLAGS = $(LTLDFLAGS)
+libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c sync.c $(OS_SRC) \
+	hotplug.h hotplug.c os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h \
+	$(THREADS_SRC) os/poll_posix.h os/poll_windows.h
+
+hdrdir = $(includedir)/libusb-1.0
+hdr_HEADERS = libusb.h

+ 2049 - 0
compat/libusb-1.0/libusb/core.c

@@ -0,0 +1,2049 @@
+/* -*- Mode: C; indent-tabs-mode:nil ; c-basic-offset:8 -*- */
+/*
+ * Core functions for libusb
+ * Copyright (c) 2012-2013 Nathan Hjelm <hjelmn@cs.unm.edu>
+ * 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>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include "libusbi.h"
+#include "hotplug.h"
+
+#if defined(OS_LINUX)
+const struct usbi_os_backend * const usbi_backend = &linux_usbfs_backend;
+#elif defined(OS_DARWIN)
+const struct usbi_os_backend * const usbi_backend = &darwin_backend;
+#elif defined(OS_OPENBSD)
+const struct usbi_os_backend * const usbi_backend = &openbsd_backend;
+#elif defined(OS_WINDOWS)
+const struct usbi_os_backend * const usbi_backend = &windows_backend;
+#else
+#error "Unsupported OS"
+#endif
+
+const struct libusb_version libusb_version_internal = {
+	LIBUSB_MAJOR, LIBUSB_MINOR, LIBUSB_MICRO, LIBUSB_NANO, LIBUSB_RC,
+	LIBUSB_DESCRIBE
+};
+
+struct libusb_context *usbi_default_context = NULL;
+static int default_context_refcnt = 0;
+static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER;
+
+usbi_mutex_static_t active_contexts_lock = USBI_MUTEX_INITIALIZER;
+struct list_head active_contexts_list;
+
+/**
+ * \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
+ * - Hotplug support (see \ref hotplug)
+ *
+ * \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 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.
+ *
+ * \section zlp Zero length packets
+ *
+ * - libusb is able to send a packet of zero length to an endpoint simply by
+ * submitting a transfer of zero length. On Linux, this did not work with
+ * libusb versions prior to 1.0.3 and kernel versions prior to 2.6.31.
+ * - The \ref libusb_transfer_flags::LIBUSB_TRANSFER_ADD_ZERO_PACKET
+ * "LIBUSB_TRANSFER_ADD_ZERO_PACKET" flag is currently only supported on Linux.
+ */
+
+/**
+ * \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 = calloc(1, 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;
+	dev->speed = LIBUSB_SPEED_UNKNOWN;
+	memset(&dev->os_priv, 0, priv_size);
+
+	if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+		usbi_connect_device (dev);
+	}
+
+	return dev;
+}
+
+void usbi_connect_device(struct libusb_device *dev)
+{
+        libusb_hotplug_message message = {LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, dev};
+        int ret;
+
+	dev->attached = 1;
+
+	usbi_mutex_lock(&dev->ctx->usb_devs_lock);
+	list_add(&dev->list, &dev->ctx->usb_devs);
+	usbi_mutex_unlock(&dev->ctx->usb_devs_lock);
+
+        /* Signal that an event has occurred for this device if we support hotplug AND
+           the hotplug pipe is ready. This prevents an event from getting raised during
+           initial enumeration. */
+	if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) && dev->ctx->hotplug_pipe[1] > 0) {
+                ret = usbi_write(dev->ctx->hotplug_pipe[1], &message, sizeof (message));
+                if (sizeof (message) != ret) {
+                        usbi_err(DEVICE_CTX(dev), "error writing hotplug message");
+                }
+        }
+}
+
+void usbi_disconnect_device(struct libusb_device *dev)
+{
+        libusb_hotplug_message message = {LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, dev};
+	struct libusb_context *ctx = dev->ctx;
+        int ret;
+
+	usbi_mutex_lock(&dev->lock);
+	dev->attached = 0;
+	usbi_mutex_unlock(&dev->lock);
+
+        /* Signal that an event has occurred for this device if we support hotplug AND
+           the hotplug pipe is ready. This prevents an event from getting raised during
+           initial enumeration. libusb_handle_events will take care of dereferencing the
+           device. */
+	if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) && dev->ctx->hotplug_pipe[1] > 0) {
+                ret = usbi_write(dev->ctx->hotplug_pipe[1], &message, sizeof (message));
+                if (sizeof(message) != ret) {
+                        usbi_err(DEVICE_CTX(dev), "error writing hotplug message");
+                }
+        }
+
+	usbi_mutex_lock(&ctx->usb_devs_lock);
+	list_del(&dev->list);
+	usbi_mutex_unlock(&ctx->usb_devs_lock);
+}
+
+/* Perform some final sanity checks on a newly discovered device. If this
+ * 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;
+	uint8_t num_configurations;
+
+	r = usbi_device_cache_descriptor(dev);
+	if (r < 0)
+		return r;
+
+	num_configurations = dev->device_descriptor.bNumConfigurations;
+	if (num_configurations > USB_MAXCONFIG) {
+		usbi_err(DEVICE_CTX(dev), "too many configurations");
+		return LIBUSB_ERROR_IO;
+	} else if (0 == num_configurations)
+		usbi_dbg("zero configurations, maybe an unauthorized device");
+
+	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 any
+ * \ref libusb_error according to errors encountered by the backend.
+ */
+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;
+
+	if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+		/* backend provides hotplug support */
+		struct libusb_device *dev;
+
+		usbi_mutex_lock(&ctx->usb_devs_lock);
+		list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) {
+			discdevs = discovered_devs_append(discdevs, dev);
+
+			if (!discdevs) {
+				r = LIBUSB_ERROR_NO_MEM;
+				break;
+			}
+		}
+		usbi_mutex_unlock(&ctx->usb_devs_lock);
+	} else {
+		/* backend does not provide hotplug support */
+		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;
+}
+
+/** \ingroup dev
+ * Get the negotiated connection speed for a device.
+ * \param dev a device
+ * \returns a \ref libusb_speed code, where LIBUSB_SPEED_UNKNOWN means that
+ * the OS doesn't know or doesn't support returning the negotiated speed.
+ */
+int API_EXPORTED libusb_get_device_speed(libusb_device *dev)
+{
+	return dev->speed;
+}
+
+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);
+
+		if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+			/* backend does not support hotplug */
+			usbi_disconnect_device(dev);
+		}
+
+		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);
+
+	if (!dev->attached) {
+		return LIBUSB_ERROR_NO_DEVICE;
+	}
+
+	_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) {
+		usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r);
+		libusb_unref_device(dev);
+		usbi_mutex_destroy(&_handle->lock);
+		free(_handle);
+		return r;
+	}
+
+	usbi_mutex_lock(&ctx->open_devs_lock);
+	list_add(&_handle->list, &ctx->open_devs);
+	usbi_mutex_unlock(&ctx->open_devs_lock);
+	*handle = _handle;
+
+	/* 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)
+{
+	struct usbi_transfer *itransfer;
+	struct usbi_transfer *tmp;
+
+	libusb_lock_events(ctx);
+
+	/* remove any transfers in flight that are for this device */
+	usbi_mutex_lock(&ctx->flying_transfers_lock);
+
+	/* safe iteration because transfers may be being deleted */
+	list_for_each_entry_safe(itransfer, tmp, &ctx->flying_transfers, list, struct usbi_transfer) {
+		struct libusb_transfer *transfer =
+		        USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+		if (transfer->dev_handle != dev_handle)
+			continue;
+
+		if (!(itransfer->flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) {
+			usbi_err(ctx, "Device handle closed while transfer was still being processed, but the device is still connected as far as we know");
+
+			if (itransfer->flags & USBI_TRANSFER_CANCELLING)
+				usbi_warn(ctx, "A cancellation for an in-flight transfer hasn't completed but closing the device handle");
+			else
+				usbi_err(ctx, "A cancellation hasn't even been scheduled on the transfer for which the device is closing");
+		}
+
+		/* remove from the list of in-flight transfers and make sure
+		 * we don't accidentally use the device handle in the future
+		 * (or that such accesses will be easily caught and identified as a crash)
+		 */
+		usbi_mutex_lock(&itransfer->lock);
+		list_del(&itransfer->list);
+		transfer->dev_handle = NULL;
+		usbi_mutex_unlock(&itransfer->lock);
+
+		/* it is up to the user to free up the actual transfer struct.  this is
+		 * just making sure that we don't attempt to process the transfer after
+		 * the device handle is invalid
+		 */
+		usbi_dbg("Removed transfer %p from the in-flight list because device handle %p closed",
+			 transfer, dev_handle);
+	}
+	usbi_mutex_unlock(&ctx->flying_transfers_lock);
+
+	libusb_unlock_events(ctx);
+
+	usbi_mutex_lock(&ctx->open_devs_lock);
+	list_del(&dev_handle->list);
+	usbi_mutex_unlock(&ctx->open_devs_lock);
+
+	usbi_backend->close(dev_handle);
+	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 >= USB_MAXINTERFACES)
+		return LIBUSB_ERROR_INVALID_PARAM;
+
+	if (!dev->dev->attached)
+		return LIBUSB_ERROR_NO_DEVICE;
+
+	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 >= USB_MAXINTERFACES)
+		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 >= USB_MAXINTERFACES)
+		return LIBUSB_ERROR_INVALID_PARAM;
+
+	usbi_mutex_lock(&dev->lock);
+	if (!dev->dev->attached) {
+		usbi_mutex_unlock(&dev->lock);
+		return LIBUSB_ERROR_NO_DEVICE;
+	}
+
+	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);
+	if (!dev->dev->attached)
+		return LIBUSB_ERROR_NO_DEVICE;
+
+	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("");
+	if (!dev->dev->attached)
+		return LIBUSB_ERROR_NO_DEVICE;
+
+	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 (!dev->dev->attached)
+		return LIBUSB_ERROR_NO_DEVICE;
+
+	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 (!dev->dev->attached)
+		return LIBUSB_ERROR_NO_DEVICE;
+
+	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 (!dev->dev->attached)
+		return LIBUSB_ERROR_NO_DEVICE;
+
+	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)
+{
+	struct libusb_device *dev, *next;
+	char *dbg = getenv("LIBUSB_DEBUG");
+	struct libusb_context *ctx;
+	static int first_init = 1;
+	int r = 0;
+
+	usbi_mutex_static_lock(&default_context_lock);
+	if (!context && usbi_default_context) {
+		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;
+	}
+
+	usbi_dbg("libusb-%d.%d.%d%s%s%s",
+	         libusb_version_internal.major,
+	         libusb_version_internal.minor,
+	         libusb_version_internal.micro,
+	         libusb_version_internal.rc,
+	         libusb_version_internal.describe[0] ? " git:" : "",
+	         libusb_version_internal.describe);
+
+	usbi_mutex_init(&ctx->usb_devs_lock, NULL);
+	usbi_mutex_init(&ctx->open_devs_lock, NULL);
+	usbi_mutex_init(&ctx->hotplug_cbs_lock, NULL);
+	list_init(&ctx->usb_devs);
+	list_init(&ctx->open_devs);
+	list_init(&ctx->hotplug_cbs);
+
+	if (usbi_backend->init) {
+		r = usbi_backend->init(ctx);
+		if (r)
+			goto err_free_ctx;
+	}
+
+	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);
+
+	usbi_mutex_static_lock(&active_contexts_lock);
+	if (first_init) {
+		first_init = 0;
+		list_init (&active_contexts_list);
+	}
+
+	list_add (&ctx->list, &active_contexts_list);
+	usbi_mutex_static_unlock(&active_contexts_lock);
+
+	return 0;
+
+err_destroy_mutex:
+	usbi_mutex_destroy(&ctx->open_devs_lock);
+	usbi_mutex_destroy(&ctx->usb_devs_lock);
+err_free_ctx:
+	usbi_mutex_lock(&ctx->usb_devs_lock);
+	list_for_each_entry_safe(dev, next, &ctx->usb_devs, list, struct libusb_device) {
+		list_del(&dev->list);
+		libusb_unref_device(dev);
+	}
+	usbi_mutex_unlock(&ctx->usb_devs_lock);
+	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)
+{
+	struct libusb_device *dev, *next;
+
+	usbi_dbg("");
+	USBI_GET_CONTEXT(ctx);
+
+	/* 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);
+	}
+
+	usbi_mutex_static_lock(&active_contexts_lock);
+	list_del (&ctx->list);
+	usbi_mutex_static_unlock(&active_contexts_lock);
+
+	usbi_hotplug_deregister_all(ctx);
+
+	usbi_mutex_lock(&ctx->usb_devs_lock);
+	list_for_each_entry_safe(dev, next, &ctx->usb_devs, list, struct libusb_device) {
+		list_del(&dev->list);
+		libusb_unref_device(dev);
+	}
+	usbi_mutex_unlock(&ctx->usb_devs_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);
+	usbi_mutex_destroy(&ctx->hotplug_cbs_lock);
+	free(ctx);
+}
+
+/** \ingroup misc
+ * Check at runtime if the loaded library has a given capability.
+ *
+ * \param capability the \ref libusb_capability to check for
+ * \returns 1 if the running library has the capability, 0 otherwise
+ */
+int API_EXPORTED libusb_has_capability(uint32_t capability)
+{
+	enum libusb_capability cap = capability;
+	switch (cap) {
+	case LIBUSB_CAP_HAS_CAPABILITY:
+		return 1;
+	case LIBUSB_CAP_HAS_HOTPLUG:
+		return !(usbi_backend->get_device_list);
+	}
+	return 0;
+}
+
+/* this is defined in libusbi.h if needed */
+#ifdef LIBUSB_GETTIMEOFDAY_WIN32
+/*
+ * gettimeofday
+ * Implementation according to:
+ * The Open Group Base Specifications Issue 6
+ * IEEE Std 1003.1, 2004 Edition
+ */
+
+/*
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *  Contributed by:
+ *  Danny Smith <dannysmith@users.sourceforge.net>
+ */
+
+/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
+#define _W32_FT_OFFSET (116444736000000000)
+
+int usbi_gettimeofday(struct timeval *tp, void *tzp)
+ {
+  union {
+    unsigned __int64 ns100; /*time since 1 Jan 1601 in 100ns units */
+    FILETIME ft;
+  }  _now;
+
+  if(tp)
+    {
+      GetSystemTimeAsFileTime (&_now.ft);
+      tp->tv_usec=(long)((_now.ns100 / 10) % 1000000 );
+      tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000);
+    }
+  /* Always return 0 as per Open Group Base Specifications Issue 6.
+     Do not set errno on error.  */
+  return 0;
+}
+#endif
+
+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;
+	struct timeval now;
+	static struct timeval first = { 0, 0 };
+
+#ifndef ENABLE_DEBUG_LOGGING
+	USBI_GET_CONTEXT(ctx);
+	if (!ctx)
+		return;
+	if (!ctx->debug)
+		return;
+	if (level == LOG_LEVEL_WARNING && ctx->debug < 2)
+		return;
+	if (level == LOG_LEVEL_INFO && ctx->debug < 3)
+		return;
+#endif
+
+	usbi_gettimeofday(&now, NULL);
+	if (!first.tv_sec) {
+		first.tv_sec = now.tv_sec;
+		first.tv_usec = now.tv_usec;
+	}
+	if (now.tv_usec < first.tv_usec) {
+		now.tv_sec--;
+		now.tv_usec += 1000000;
+	}
+	now.tv_sec -= first.tv_sec;
+	now.tv_usec -= first.tv_usec;
+
+	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: %d.%06d %s [%s] ",
+		(int)now.tv_sec, (int)now.tv_usec, 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 the ASCII name of a libusb
+ * error code. The caller must not free() the returned string.
+ *
+ * \param error_code The \ref libusb_error code to return the name of.
+ * \returns The error name, or the string **UNKNOWN** if the value of
+ * error_code is not a known error code.
+ */
+DEFAULT_VISIBILITY const char * LIBUSB_CALL libusb_error_name(int error_code)
+{
+	enum libusb_error error = error_code;
+	switch (error) {
+	case LIBUSB_SUCCESS:
+		return "LIBUSB_SUCCESS";
+	case LIBUSB_ERROR_IO:
+		return "LIBUSB_ERROR_IO";
+	case LIBUSB_ERROR_INVALID_PARAM:
+		return "LIBUSB_ERROR_INVALID_PARAM";
+	case LIBUSB_ERROR_ACCESS:
+		return "LIBUSB_ERROR_ACCESS";
+	case LIBUSB_ERROR_NO_DEVICE:
+		return "LIBUSB_ERROR_NO_DEVICE";
+	case LIBUSB_ERROR_NOT_FOUND:
+		return "LIBUSB_ERROR_NOT_FOUND";
+	case LIBUSB_ERROR_BUSY:
+		return "LIBUSB_ERROR_BUSY";
+	case LIBUSB_ERROR_TIMEOUT:
+		return "LIBUSB_ERROR_TIMEOUT";
+	case LIBUSB_ERROR_OVERFLOW:
+		return "LIBUSB_ERROR_OVERFLOW";
+	case LIBUSB_ERROR_PIPE:
+		return "LIBUSB_ERROR_PIPE";
+	case LIBUSB_ERROR_INTERRUPTED:
+		return "LIBUSB_ERROR_INTERRUPTED";
+	case LIBUSB_ERROR_NO_MEM:
+		return "LIBUSB_ERROR_NO_MEM";
+	case LIBUSB_ERROR_NOT_SUPPORTED:
+		return "LIBUSB_ERROR_NOT_SUPPORTED";
+	case LIBUSB_ERROR_OTHER:
+		return "LIBUSB_ERROR_OTHER";
+	}
+	return "**UNKNOWN**";
+}
+
+/** \ingroup misc
+ * Returns a constant 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 dot.
+ * \param errcode the error code whose description is desired
+ * \returns a short description of the error code in English
+ */
+API_EXPORTED const char* libusb_strerror(enum libusb_error errcode)
+{
+	switch (errcode) {
+	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
+ * Returns a pointer to const struct libusb_version with the version
+ * (major, minor, micro, rc, and nano) of the running library.
+ */
+DEFAULT_VISIBILITY
+const struct libusb_version * LIBUSB_CALL libusb_get_version(void)
+{
+	return &libusb_version_internal;
+}

+ 871 - 0
compat/libusb-1.0/libusb/descriptor.c

@@ -0,0 +1,871 @@
+/*
+ * USB descriptor handling functions for libusb
+ * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ * Copyright (c) 2012-2013 Nathan Hjelm <hjelmn@cs.unm.edu>
+ *
+ * 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 <stdio.h>
+#include <assert.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(const unsigned char *source, const char *descriptor,
+	void *dest, int host_endian)
+{
+	const unsigned char *sp = source;
+	unsigned char *dp = dest;
+	uint16_t w;
+	const char *cp;
+	uint32_t d;
+
+	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;
+			/* 32-bit word, convert from little endian to CPU */
+			case 'd':
+			/* Align to word boundary */
+				dp += ((unsigned long)dp & 1);
+
+				if (host_endian) {
+					memcpy(dp, sp, 4);
+				} else {
+					d = (sp[3] << 24) | (sp[2] << 16) |
+						(sp[1] << 8) | sp[0];
+					*((uint32_t *)dp) = d;
+				}
+				sp += 4;
+				dp += 4;
+				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;
+	size_t 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) ||
+			    (header.bDescriptorType ==
+			     LIBUSB_DT_SS_ENDPOINT_COMPANION))
+				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? */
+		if (size >= DESC_HEADER_LENGTH) {
+			usbi_parse_descriptor(buffer, "bb", &header, 0);
+			if ((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;
+	size_t 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) ||
+			    (header.bDescriptorType ==
+			     LIBUSB_DT_SS_ENDPOINT_COMPANION))
+				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;
+}
+
+int usbi_device_cache_descriptor(libusb_device *dev)
+{
+	int r, host_endian;
+
+	r = usbi_backend->get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor,
+						&host_endian);
+	if (r < 0)
+		return r;
+
+	if (!host_endian) {
+		dev->device_descriptor.bcdUSB = libusb_le16_to_cpu(dev->device_descriptor.bcdUSB);
+		dev->device_descriptor.idVendor = libusb_le16_to_cpu(dev->device_descriptor.idVendor);
+		dev->device_descriptor.idProduct = libusb_le16_to_cpu(dev->device_descriptor.idProduct);
+		dev->device_descriptor.bcdDevice = libusb_le16_to_cpu(dev->device_descriptor.bcdDevice);
+	}
+
+	return LIBUSB_SUCCESS;
+}
+
+/** \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)
+{
+	usbi_dbg("");
+	memcpy((unsigned char *) desc, (unsigned char *) &dev->device_descriptor,
+	       sizeof (dev->device_descriptor));
+	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. Language
+	 * IDs are 16 bit numbers, and they start at the third byte in the
+	 * descriptor. There's also no point in trying to read descriptor 0
+	 * with this function. See USB 2.0 specification section 9.6.7 for
+	 * more information.
+	 */
+
+	if (desc_index == 0)
+		return LIBUSB_ERROR_INVALID_PARAM;
+
+	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;
+}
+
+int API_EXPORTED libusb_parse_ss_endpoint_comp(const void *buf, int len,
+					       struct libusb_ss_endpoint_companion_descriptor **ep_comp)
+{
+	struct libusb_ss_endpoint_companion_descriptor *ep_comp_desc;
+	struct usb_descriptor_header header;
+
+	usbi_parse_descriptor(buf, "bb", &header, 0);
+
+	/* Everything should be fine being passed into here, but we sanity */
+	/*  check JIC */
+	if (header.bLength > len) {
+		usbi_err(NULL, "ran out of descriptors parsing");
+		return LIBUSB_ERROR_NO_MEM;
+	}
+
+	if (header.bDescriptorType != LIBUSB_DT_SS_ENDPOINT_COMPANION) {
+		usbi_err(NULL, "unexpected descriptor %x (expected %x)",
+			header.bDescriptorType, LIBUSB_DT_SS_ENDPOINT_COMPANION);
+		return LIBUSB_ERROR_INVALID_PARAM;
+	}
+
+	ep_comp_desc = calloc(1, sizeof (*ep_comp_desc));
+	if (!ep_comp_desc) {
+		return LIBUSB_ERROR_NO_MEM;
+	}
+
+	if (header.bLength >= LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE)
+		usbi_parse_descriptor(buf, "bbbbw", ep_comp_desc, 0);
+
+	*ep_comp = ep_comp_desc;
+
+	return LIBUSB_SUCCESS;
+}
+
+void API_EXPORTED libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp)
+{
+	assert(ep_comp);
+	free(ep_comp);
+}
+
+int API_EXPORTED libusb_parse_bos_descriptor(const void *buf, int len,
+                                             struct libusb_bos_descriptor **bos)
+{
+	const unsigned char *buffer = (const unsigned char *) buf;
+	struct libusb_bos_descriptor *bos_desc;
+	int i;
+
+	bos_desc = calloc (1, sizeof (*bos_desc));
+	if (!bos_desc) {
+		return LIBUSB_ERROR_NO_MEM;
+	}
+
+	usbi_parse_descriptor(buffer, "bbwb", bos_desc, 0);
+	buffer += LIBUSB_DT_BOS_SIZE;
+
+	/* Get the device capability descriptors */
+	for (i = 0; i < bos_desc->bNumDeviceCaps; ++i) {
+		if (buffer[2] == LIBUSB_USB_CAP_TYPE_EXT) {
+			if (!bos_desc->usb_2_0_ext_cap) {
+				bos_desc->usb_2_0_ext_cap =
+					(struct libusb_usb_2_0_device_capability_descriptor *)
+					malloc(sizeof(*bos_desc->usb_2_0_ext_cap));
+				usbi_parse_descriptor(buffer, "bbbd",
+						      bos_desc->usb_2_0_ext_cap, 0);
+			} else
+				usbi_warn(NULL,
+					  "usb_2_0_ext_cap was already allocated");
+
+			/* move to the next device capability descriptor */
+			buffer += LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE;
+		} else if (buffer[2] == LIBUSB_SS_USB_CAP_TYPE) {
+			if (!bos_desc->ss_usb_cap) {
+				bos_desc->ss_usb_cap =
+					(struct libusb_ss_usb_device_capability_descriptor *)
+					malloc(sizeof(*bos_desc->ss_usb_cap));
+				usbi_parse_descriptor(buffer, "bbbbwbbw",
+						      bos_desc->ss_usb_cap, 0);
+			} else
+				usbi_warn(NULL,
+					  "ss_usb_cap was already allocated");
+
+			/* move to the next device capability descriptor */
+			buffer += LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE;
+		} else {
+			usbi_info(NULL, "wireless/container_id capability "
+				  "descriptor");
+
+			/* move to the next device capability descriptor */
+			buffer += buffer[0];
+		}
+	}
+
+	*bos = bos_desc;
+
+	return LIBUSB_SUCCESS;
+}
+
+void API_EXPORTED libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos)
+{
+	assert(bos);
+
+	if (bos->usb_2_0_ext_cap) {
+		free(bos->usb_2_0_ext_cap);
+	}
+
+	if (bos->ss_usb_cap) {
+		free(bos->ss_usb_cap);
+	}
+
+	free(bos);
+}

+ 298 - 0
compat/libusb-1.0/libusb/hotplug.c

@@ -0,0 +1,298 @@
+/* -*- Mode: C; indent-tabs-mode:nil ; c-basic-offset:8 -*- */
+/*
+ * Hotplug functions for libusb
+ * Copyright (C) 2012-2013 Nathan Hjelm <hjelmn@mac.com>
+ * Copyright (C) 2012-2013 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
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <assert.h>
+
+#include "libusbi.h"
+#include "hotplug.h"
+
+/**
+ * @defgroup hotplug  Device hotplug event notification
+ * This page details how to use the libusb hotplug interface.
+ *
+ * \page hotplug Device hotplug event notification
+ *
+ * \section intro Introduction
+ *
+ * Releases of libusb 1.0 newer than 1.X have added support for hotplug
+ * events. This interface allows you to request notification for the
+ * arrival and departure of matching USB devices.
+ *
+ * To receive hotplug notification you register a callback by calling
+ * libusb_hotplug_register_callback(). This function will optionally return
+ * a handle that can be passed to libusb_hotplug_deregister_callback().
+ *
+ * A callback function must return an int (0 or 1) indicating whether the callback is
+ * expecting additional events. Returning 0 will rearm the callback and 1 will cause
+ * the callback to be deregistered.
+ *
+ * Callbacks for a particulat context are automatically deregistered by libusb_exit().
+ *
+ * As of 1.X there are two supported hotplug events:
+ *  - LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: A device has arrived and is ready to use
+ *  - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: A device has left and is no longer available
+ *
+ * A hotplug event can listen for either or both of these events.
+ *
+ * Note: If you receive notification that a device has left and you have any
+ * a libusb_device_handles for the device it is up to you to call libusb_close()
+ * on each handle to free up any remaining resources associated with the device.
+ * Once a device has left any libusb_device_handle associated with the device
+ * are invalid and will remain so even if the device comes back.
+ *
+ * When handling a LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED event it is considered
+ * safe to call any libusb function that takes a libusb_device. On the other hand,
+ * when handling a LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT event the only safe function
+ * is libusb_get_device_descriptor().
+ *
+ * The following code provides an example of the usage of the hotplug interface:
+\code
+static int count = 0;
+
+int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev,
+                     libusb_hotplug_event event, void *user_data) {
+  static libusb_device_handle *handle = NULL;
+  struct libusb_device_descriptor desc;
+  int rc;
+
+  (void)libusb_get_device_descriptor(dev, &desc);
+
+  if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == event) {
+    rc = libusb_open(dev, &handle);
+    if (LIBUSB_SUCCESS != rc) {
+      printf("Could not open USB device\n");
+    }
+  } else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) {
+    if (handle) {
+      libusb_close(handle);
+      handle = NULL;
+    }
+  } else {
+    printf("Unhandled event %d\n", event);
+  }
+  count++;
+
+  return 0;
+}
+
+int main (void) {
+  libusb_hotplug_callback_handle handle;
+  int rc;
+
+  libusb_init(NULL);
+
+  rc = libusb_hotplug_register_callback(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
+                                        LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, 0x045a, 0x5005,
+                                        LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, NULL,
+                                        &handle);
+  if (LIBUSB_SUCCESS != rc) {
+    printf("Error creating a hotplug callback\n");
+    libusb_exit(NULL);
+    return EXIT_FAILURE;
+  }
+
+  while (count < 2) {
+    usleep(10000);
+  }
+
+  libusb_hotplug_deregister_callback(handle);
+  libusb_exit(NULL);
+
+  return 0;
+}
+\endcode
+ */
+
+static int usbi_hotplug_match_cb (struct libusb_device *dev, libusb_hotplug_event event,
+                                   struct libusb_hotplug_callback *hotplug_cb) {
+	struct libusb_context *ctx = dev->ctx;
+
+        /* Handle lazy deregistration of callback */
+        if (hotplug_cb->needs_free) {
+                /* Free callback */
+                return 1;
+        }
+
+        if (!(hotplug_cb->events & event)) {
+                return 0;
+        }
+
+        if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->vendor_id &&
+            hotplug_cb->vendor_id != dev->device_descriptor.idVendor) {
+                return 0;
+        }
+
+        if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->product_id &&
+            hotplug_cb->product_id != dev->device_descriptor.idProduct) {
+                return 0;
+        }
+
+        if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->dev_class &&
+            hotplug_cb->dev_class != dev->device_descriptor.bDeviceClass) {
+                return 0;
+        }
+
+        return hotplug_cb->cb (ctx == usbi_default_context ? NULL : ctx,
+                             dev, event, hotplug_cb->user_data);
+}
+
+void usbi_hotplug_match(struct libusb_device *dev, libusb_hotplug_event event) {
+	struct libusb_hotplug_callback *hotplug_cb, *next;
+	struct libusb_context *ctx = dev->ctx;
+
+	usbi_mutex_lock(&ctx->hotplug_cbs_lock);
+
+	list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
+                usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
+                int ret = usbi_hotplug_match_cb (dev, event, hotplug_cb);
+                usbi_mutex_lock(&ctx->hotplug_cbs_lock);
+
+                if (ret) {
+                        list_del(&hotplug_cb->list);
+                        free(hotplug_cb);
+                }
+	}
+
+	usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
+
+        /* loop through and disconnect all open handles for this device */
+        if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) {
+                struct libusb_device_handle *handle;
+
+                usbi_mutex_lock(&ctx->open_devs_lock);
+                list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
+                        if (dev == handle->dev) {
+                                usbi_handle_disconnect (handle);
+                        }
+                }
+                usbi_mutex_unlock(&ctx->open_devs_lock);
+        }
+}
+
+int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
+                                                  libusb_hotplug_event events,
+                                                  libusb_hotplug_flag flags,
+                                                  int vendor_id, int product_id,
+                                                  int dev_class,
+                                                  libusb_hotplug_callback_fn cb_fn,
+                                                  void *user_data, libusb_hotplug_callback_handle *handle) {
+        libusb_hotplug_callback *new_callback;
+        static int handle_id = 1;
+
+        /* check for hotplug support */
+        if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+                return LIBUSB_ERROR_NOT_SUPPORTED;
+        }
+
+        /* check for sane values */
+        if ((LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) ||
+            (LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) ||
+            (LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) ||
+            !cb_fn) {
+                return LIBUSB_ERROR_INVALID_PARAM;
+        }
+
+        USBI_GET_CONTEXT(ctx);
+
+        new_callback = (libusb_hotplug_callback *)calloc(1, sizeof (*new_callback));
+        if (!new_callback) {
+                return LIBUSB_ERROR_NO_MEM;
+        }
+
+        new_callback->ctx = ctx;
+        new_callback->vendor_id = vendor_id;
+        new_callback->product_id = product_id;
+        new_callback->dev_class = dev_class;
+        new_callback->flags = flags;
+        new_callback->events = events;
+        new_callback->cb = cb_fn;
+        new_callback->user_data = user_data;
+        new_callback->needs_free = 0;
+
+	usbi_mutex_lock(&ctx->hotplug_cbs_lock);
+
+        /* protect the handle by the context hotplug lock. it doesn't matter if the same handle is used for different
+           contexts only that the handle is unique for this context */
+        new_callback->handle = handle_id++;
+
+	list_add(&new_callback->list, &ctx->hotplug_cbs);
+
+        if (flags & LIBUSB_HOTPLUG_ENUMERATE) {
+                struct libusb_device *dev;
+
+                usbi_mutex_lock(&ctx->usb_devs_lock);
+
+                list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) {
+                        (void) usbi_hotplug_match_cb (dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, new_callback);
+                }
+
+                usbi_mutex_unlock(&ctx->usb_devs_lock);
+        }
+
+	usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
+
+        if (handle) {
+                *handle = new_callback->handle;
+        }
+
+        return LIBUSB_SUCCESS;
+}
+
+void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx, libusb_hotplug_callback_handle handle) {
+        struct libusb_hotplug_callback *hotplug_cb;
+
+        /* check for hotplug support */
+        if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+                return;
+        }
+
+        USBI_GET_CONTEXT(ctx);
+
+        usbi_mutex_lock(&ctx->hotplug_cbs_lock);
+        list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list,
+                            struct libusb_hotplug_callback) {
+                if (handle == hotplug_cb->handle) {
+                        /* Mark this callback for deregistration */
+                        hotplug_cb->needs_free = 1;
+                }
+        }
+        usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
+}
+
+void usbi_hotplug_deregister_all(struct libusb_context *ctx) {
+	struct libusb_hotplug_callback *hotplug_cb, *next;
+
+	usbi_mutex_lock(&ctx->hotplug_cbs_lock);
+	list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list,
+				 struct libusb_hotplug_callback) {
+		list_del(&hotplug_cb->list);
+                free(hotplug_cb);
+	}
+
+	usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
+}

+ 77 - 0
compat/libusb-1.0/libusb/hotplug.h

@@ -0,0 +1,77 @@
+/* -*- Mode: C; indent-tabs-mode:nil ; c-basic-offset:8 -*- */
+/*
+ * Hotplug support for libusb 1.0
+ * Copyright (C) 2012      Nathan Hjelm <hjelmn@users.sourceforge.net>
+ * Copyright (C) 2012      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
+ */
+
+#if !defined(USBI_HOTPLUG_H)
+#define USBI_HOTPLUG_H
+
+/** \ingroup hotplug
+ * The hotplug callback structure. The user populates this structure with
+ * libusb_hotplug_prepare_callback() and then calls libusb_hotplug_register_callback()
+ * to receive notification of hotplug events.
+ */
+struct libusb_hotplug_callback {
+	/** Context this callback is associated with */
+	struct libusb_context *ctx;
+
+	/** Vendor ID to match or LIBUSB_HOTPLUG_MATCH_ANY */
+	int vendor_id;
+
+	/** Product ID to match or LIBUSB_HOTPLUG_MATCH_ANY */
+	int product_id;
+
+	/** Device class to match or LIBUSB_HOTPLUG_MATCH_ANY */
+	int dev_class;
+
+	/** Hotplug callback flags */
+        libusb_hotplug_flag flags;
+
+	/** Event(s) that will trigger this callback */
+	libusb_hotplug_event events;
+
+	/** Callback function to invoke for matching event/device */
+	libusb_hotplug_callback_fn cb;
+
+        /** Handle for this callback (used to match on deregister) */
+        libusb_hotplug_callback_handle handle;
+
+	/** User data that will be passed to the callback function */
+	void *user_data;
+
+        /** Callback is marked for deletion */
+        int needs_free;
+
+	/** List this callback is registered in (ctx->hotplug_cbs) */
+        struct list_head list;
+};
+
+typedef struct libusb_hotplug_callback libusb_hotplug_callback;
+
+struct libusb_hotplug_message {
+        libusb_hotplug_event event;
+        struct libusb_device *device;
+};
+
+typedef struct libusb_hotplug_message libusb_hotplug_message;
+
+void usbi_hotplug_deregister_all(struct libusb_context *ctx);
+void usbi_hotplug_match(struct libusb_device *dev, libusb_hotplug_event event);
+
+#endif

+ 2500 - 0
compat/libusb-1.0/libusb/io.c

@@ -0,0 +1,2500 @@
+/*
+ * 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>
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef USBI_TIMERFD_AVAILABLE
+#include <sys/timerfd.h>
+#endif
+
+#include "libusbi.h"
+#include "hotplug.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, LIBUSB_ENDPOINT_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, &zero_tv);
+	if (time has elapsed to or beyond the libusb timeout)
+		libusb_handle_events_timeout(ctx, &zero_tv);
+	// 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, &zero_tv);
+	// 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, &zero_tv);
+	}
+	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 its variants, and all the
+ * synchronous I/O functions - libusb hides this headache from you.
+ *
+ * \section Using libusb_handle_events() from multiple threads
+ *
+ * Even when only using libusb_handle_events() and synchronous I/O functions,
+ * you can still have a race condition. You might be tempted to solve the
+ * above with libusb_handle_events() like so:
+ *
+\code
+	libusb_submit_transfer(transfer);
+
+	while (!completed) {
+		libusb_handle_events(ctx);
+	}
+	printf("completed!");
+\endcode
+ *
+ * This however has a race between the checking of completed and
+ * libusb_handle_events() acquiring the events lock, so another thread
+ * could have completed the transfer, resulting in this thread hanging
+ * until either a timeout or another event occurs. See also commit
+ * 6696512aade99bb15d6792af90ae329af270eba6 which fixes this in the
+ * synchronous API implementation of libusb.
+ *
+ * Fixing this race requires checking the variable completed only after
+ * taking the event lock, which defeats the concept of just calling
+ * libusb_handle_events() without worrying about locking. This is why
+ * libusb-1.0.9 introduces the new libusb_handle_events_timeout_completed()
+ * and libusb_handle_events_completed() functions, which handles doing the
+ * completion check for you after they have acquired the lock:
+ *
+\code
+	libusb_submit_transfer(transfer);
+
+	while (!completed) {
+		libusb_handle_events_completed(ctx, &completed);
+	}
+	printf("completed!");
+\endcode
+ *
+ * This nicely fixes the race in our example. Note that if all you want to
+ * do is submit a single transfer and wait for its completion, then using
+ * one of the synchronous I/O functions is much easier.
+ *
+ * \section eventlock The events lock
+ *
+ * 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.
+ *
+ * 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, &zero_tv);
+	}
+	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_recursive(&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;
+
+        /* create hotplug pipe */
+        r = usbi_pipe(ctx->hotplug_pipe);
+	if (r < 0) {
+		r = LIBUSB_ERROR_OTHER;
+		goto err;
+	}
+
+#ifndef OS_WINDOWS
+        fcntl (ctx->hotplug_pipe[1], F_SETFD, O_NONBLOCK);
+#endif
+        r = usbi_add_pollfd(ctx, ctx->hotplug_pipe[0], POLLIN);
+        if (r < 0)
+                goto err_close_hp_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_hp_pipe;
+		}
+	} else {
+		usbi_dbg("timerfd not available (code %d error %d)", ctx->timerfd, errno);
+		ctx->timerfd = -1;
+	}
+#endif
+
+	return 0;
+
+err_close_hp_pipe:
+        usbi_close(ctx->hotplug_pipe[0]);
+        usbi_close(ctx->hotplug_pipe[1]);
+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]);
+        usbi_remove_pollfd(ctx, ctx->hotplug_pipe[0]);
+	usbi_close(ctx->hotplug_pipe[0]);
+	usbi_close(ctx->hotplug_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;
+
+	while (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 LIBUSB_ERROR_NOT_SUPPORTED if the transfer flags are not supported
+ * by the operating system.
+ * \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;
+	int updated_fds;
+
+	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;
+	}
+#else
+	(void)first;
+#endif
+
+out:
+	updated_fds = (itransfer->flags & USBI_TRANSFER_UPDATED_FDS);
+	usbi_mutex_unlock(&itransfer->lock);
+	if (updated_fds)
+		usbi_fd_notification(ctx);
+	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) {
+		if (r != LIBUSB_ERROR_NOT_FOUND)
+			usbi_err(TRANSFER_CTX(transfer),
+				"cancel transfer failed error %d", r);
+		else
+			usbi_dbg("cancel transfer failed error %d", r);
+
+		if (r == LIBUSB_ERROR_NO_DEVICE)
+			itransfer->flags |= USBI_TRANSFER_DEVICE_DISAPPEARED;
+	}
+
+	itransfer->flags |= USBI_TRANSFER_CANCELLING;
+
+	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)
+{
+	(void)ctx;
+	return 0;
+}
+static int arm_timerfd_for_next_timeout(struct libusb_context *ctx)
+{
+	(void)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 = 0;
+
+	/* 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);
+	if (usbi_using_timerfd(ctx)) {
+		r = arm_timerfd_for_next_timeout(ctx);
+		if (0 == r)
+			r = disarm_timerfd(ctx);
+	}
+	usbi_mutex_unlock(&ctx->flying_transfers_lock);
+	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;
+	usbi_dbg("transfer %p has callback %p", transfer, transfer->callback);
+	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;
+	while (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);
+}
+
+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 | USBI_TRANSFER_OS_HANDLES_TIMEOUT))
+			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;
+}
+
+#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;
+	POLL_NFDS_TYPE 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--;
+		}
+	}
+
+        /* fd[1] is always the hotplug pipe */
+        if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) && fds[1].revents) {
+                libusb_hotplug_message message;
+                int ret;
+
+                /* read the message from the hotplug thread */
+                ret = read(ctx->hotplug_pipe[0], &message, sizeof (message));
+                if (ret < sizeof(message)) {
+                        ret = LIBUSB_ERROR_OTHER;
+                        goto handled;
+                }
+
+                usbi_hotplug_match(message.device, message.event);
+
+                /* the device left. dereference the device */
+                if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == message.event)
+                        libusb_unref_device(message.device);
+                
+                fds[1].revents = 0;
+                if (1 == r--)
+                        goto handled;
+        } /* else there shouldn't be anything on this pipe */
+
+#ifdef USBI_TIMERFD_AVAILABLE
+	/* on timerfd configurations, fds[2] is the timerfd */
+	if (usbi_using_timerfd(ctx) && fds[2].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[2].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.
+ *
+ * If the parameter completed is not NULL then <em>after obtaining the event
+ * handling lock</em> this function will return immediately if the integer
+ * pointed to is not 0. This allows for race free waiting for the completion
+ * of a specific transfer.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param tv the maximum time to block waiting for events, or an all zero
+ * timeval struct for non-blocking mode
+ * \param completed pointer to completion integer to check, or NULL
+ * \returns 0 on success, or a LIBUSB_ERROR code on failure
+ * \see \ref mtasync
+ */
+int API_EXPORTED libusb_handle_events_timeout_completed(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) {
+		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 thread events that
+	 * notify event completion. */
+	libusb_lock_event_waiters(ctx);
+
+	if (completed && *completed)
+		goto already_done;
+
+	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");
+	r = libusb_wait_for_event(ctx, &poll_timeout);
+
+already_done:
+	libusb_unlock_event_waiters(ctx);
+
+	if (r < 0)
+		return r;
+	else if (r == 1)
+		return handle_timeouts(ctx);
+	else
+		return 0;
+}
+
+/** \ingroup poll
+ * Handle any pending events
+ *
+ * Like libusb_handle_events_timeout_completed(), but without the completed
+ * parameter, calling this function is equivalent to calling
+ * libusb_handle_events_timeout_completed() with a NULL completed parameter.
+ *
+ * This function is kept primarily for backwards compatibility.
+ * All new code should call libusb_handle_events_completed() or
+ * libusb_handle_events_timeout_completed() to avoid race conditions.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param tv the maximum time to block waiting for events, or an all zero
+ * timeval struct for non-blocking mode
+ * \returns 0 on success, or a LIBUSB_ERROR code on failure
+ */
+int API_EXPORTED libusb_handle_events_timeout(libusb_context *ctx,
+	struct timeval *tv)
+{
+	return libusb_handle_events_timeout_completed(ctx, tv, NULL);
+}
+
+/** \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_completed()
+ * instead.
+ *
+ * This function is kept primarily for backwards compatibility.
+ * All new code should call libusb_handle_events_completed() or
+ * libusb_handle_events_timeout_completed() to avoid race conditions.
+ *
+ * \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_completed(ctx, &tv, NULL);
+}
+
+/** \ingroup poll
+ * Handle any pending events in blocking mode.
+ *
+ * Like libusb_handle_events(), with the addition of a completed parameter
+ * to allow for race free waiting for the completion of a specific transfer.
+ *
+ * See libusb_handle_events_timeout_completed() for details on the completed
+ * parameter.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param completed pointer to completion integer to check, or NULL
+ * \returns 0 on success, or a LIBUSB_ERROR code on failure
+ * \see \ref mtasync
+ */
+int API_EXPORTED libusb_handle_events_completed(libusb_context *ctx,
+	int *completed)
+{
+	struct timeval tv;
+	tv.tv_sec = 60;
+	tv.tv_usec = 0;
+	return libusb_handle_events_timeout_completed(ctx, &tv, completed);
+}
+
+/** \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_TIMERFD_AVAILABLE)
+	USBI_GET_CONTEXT(ctx);
+	return usbi_using_timerfd(ctx);
+#else
+	(void)ctx;
+	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)
+{
+	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 | USBI_TRANSFER_OS_HANDLES_TIMEOUT))
+			continue;
+
+		/* no timeout for this transfer? */
+		if (!timerisset(&transfer->timeout))
+			continue;
+
+		found = 1;
+		break;
+	}
+	usbi_mutex_unlock(&ctx->flying_transfers_lock);
+
+	if (!found) {
+		usbi_dbg("no URB with timeout or all handled by OS; no timeout!");
+		return 0;
+	}
+
+	next_timeout = &transfer->timeout;
+
+	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;
+}
+
+/** \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
+	usbi_err(ctx, "external polling of libusb's internal descriptors "\
+		"is not yet supported on Windows platforms");
+	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);
+	}
+
+}

+ 120 - 0
compat/libusb-1.0/libusb/libusb-1.0.def

@@ -0,0 +1,120 @@
+LIBRARY
+EXPORTS
+  libusb_alloc_transfer
+  libusb_alloc_transfer@4 = libusb_alloc_transfer
+  libusb_attach_kernel_driver
+  libusb_attach_kernel_driver@8 = libusb_attach_kernel_driver
+  libusb_bulk_transfer
+  libusb_bulk_transfer@24 = libusb_bulk_transfer
+  libusb_cancel_transfer
+  libusb_cancel_transfer@4 = libusb_cancel_transfer
+  libusb_claim_interface
+  libusb_claim_interface@8 = libusb_claim_interface
+  libusb_clear_halt
+  libusb_clear_halt@8 = libusb_clear_halt
+  libusb_close
+  libusb_close@4 = libusb_close
+  libusb_control_transfer
+  libusb_control_transfer@32 = libusb_control_transfer
+  libusb_detach_kernel_driver
+  libusb_detach_kernel_driver@8 = libusb_detach_kernel_driver
+  libusb_error_name
+  libusb_error_name@4 = libusb_error_name
+  libusb_event_handler_active
+  libusb_event_handler_active@4 = libusb_event_handler_active
+  libusb_event_handling_ok
+  libusb_event_handling_ok@4 = libusb_event_handling_ok
+  libusb_exit
+  libusb_exit@4 = libusb_exit
+  libusb_free_config_descriptor
+  libusb_free_config_descriptor@4 = libusb_free_config_descriptor
+  libusb_free_device_list
+  libusb_free_device_list@8 = libusb_free_device_list
+  libusb_free_transfer
+  libusb_free_transfer@4 = libusb_free_transfer
+  libusb_get_active_config_descriptor
+  libusb_get_active_config_descriptor@8 = libusb_get_active_config_descriptor
+  libusb_get_bus_number
+  libusb_get_bus_number@4 = libusb_get_bus_number
+  libusb_get_config_descriptor
+  libusb_get_config_descriptor@12 = libusb_get_config_descriptor
+  libusb_get_config_descriptor_by_value
+  libusb_get_config_descriptor_by_value@12 = libusb_get_config_descriptor_by_value
+  libusb_get_configuration
+  libusb_get_configuration@8 = libusb_get_configuration
+  libusb_get_device
+  libusb_get_device@4 = libusb_get_device
+  libusb_get_device_address
+  libusb_get_device_address@4 = libusb_get_device_address
+  libusb_get_device_descriptor
+  libusb_get_device_descriptor@8 = libusb_get_device_descriptor
+  libusb_get_device_list
+  libusb_get_device_list@8 = libusb_get_device_list
+  libusb_get_device_speed
+  libusb_get_device_speed@4 = libusb_get_device_speed
+  libusb_get_max_iso_packet_size
+  libusb_get_max_iso_packet_size@8 = libusb_get_max_iso_packet_size
+  libusb_get_max_packet_size
+  libusb_get_max_packet_size@8 = libusb_get_max_packet_size
+  libusb_get_next_timeout
+  libusb_get_next_timeout@8 = libusb_get_next_timeout
+  libusb_get_pollfds
+  libusb_get_pollfds@4 = libusb_get_pollfds
+  libusb_get_string_descriptor_ascii
+  libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii
+  libusb_get_version
+  libusb_get_version@0 = libusb_get_version
+  libusb_handle_events
+  libusb_handle_events@4 = libusb_handle_events
+  libusb_handle_events_completed
+  libusb_handle_events_completed@8 = libusb_handle_events_completed
+  libusb_handle_events_locked
+  libusb_handle_events_locked@8 = libusb_handle_events_locked
+  libusb_handle_events_timeout
+  libusb_handle_events_timeout@8 = libusb_handle_events_timeout
+  libusb_handle_events_timeout_completed
+  libusb_handle_events_timeout_completed@12 = libusb_handle_events_timeout_completed
+  libusb_has_capability
+  libusb_has_capability@4 = libusb_has_capability
+  libusb_init
+  libusb_init@4 = libusb_init
+  libusb_interrupt_transfer
+  libusb_interrupt_transfer@24 = libusb_interrupt_transfer
+  libusb_kernel_driver_active
+  libusb_kernel_driver_active@8 = libusb_kernel_driver_active
+  libusb_lock_event_waiters
+  libusb_lock_event_waiters@4 = libusb_lock_event_waiters
+  libusb_lock_events
+  libusb_lock_events@4 = libusb_lock_events
+  libusb_open
+  libusb_open@8 = libusb_open
+  libusb_open_device_with_vid_pid
+  libusb_open_device_with_vid_pid@12 = libusb_open_device_with_vid_pid
+  libusb_pollfds_handle_timeouts
+  libusb_pollfds_handle_timeouts@4 = libusb_pollfds_handle_timeouts
+  libusb_ref_device
+  libusb_ref_device@4 = libusb_ref_device
+  libusb_release_interface
+  libusb_release_interface@8 = libusb_release_interface
+  libusb_reset_device
+  libusb_reset_device@4 = libusb_reset_device
+  libusb_set_configuration
+  libusb_set_configuration@8 = libusb_set_configuration
+  libusb_set_debug
+  libusb_set_debug@8 = libusb_set_debug
+  libusb_set_interface_alt_setting
+  libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting
+  libusb_set_pollfd_notifiers
+  libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers
+  libusb_submit_transfer
+  libusb_submit_transfer@4 = libusb_submit_transfer
+  libusb_try_lock_events
+  libusb_try_lock_events@4 = libusb_try_lock_events
+  libusb_unlock_event_waiters
+  libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters
+  libusb_unlock_events
+  libusb_unlock_events@4 = libusb_unlock_events
+  libusb_unref_device
+  libusb_unref_device@4 = libusb_unref_device
+  libusb_wait_for_event
+  libusb_wait_for_event@8 = libusb_wait_for_event

+ 56 - 0
compat/libusb-1.0/libusb/libusb-1.0.rc

@@ -0,0 +1,56 @@
+/*
+ * 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 "version.h"
+#ifndef LIBUSB_VERSIONSTRING
+#define LU_STR(s) #s
+#define LU_XSTR(s) LU_STR(s)
+#if LIBUSB_NANO > 0
+#define LIBUSB_VERSIONSTRING LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." LU_XSTR(LIBUSB_MICRO) "." LU_XSTR(LIBUSB_NANO) LIBUSB_RC "\0"
+#else
+#define LIBUSB_VERSIONSTRING LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." LU_XSTR(LIBUSB_MICRO) LIBUSB_RC "\0"
+#endif
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION LIBUSB_MAJOR,LIBUSB_MINOR,LIBUSB_MICRO,LIBUSB_NANO
+ PRODUCTVERSION LIBUSB_MAJOR,LIBUSB_MINOR,LIBUSB_MICRO,LIBUSB_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", "\0"
+			VALUE "CompanyName", "libusb.org\0"
+			VALUE "FileDescription", "C library for writing portable USB drivers in userspace\0"
+			VALUE "FileVersion", LIBUSB_VERSIONSTRING
+			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\0"
+			VALUE "ProductVersion", LIBUSB_VERSIONSTRING
+			VALUE "SpecialBuild", "\0"
+		END
+	END
+	BLOCK "VarFileInfo"
+	BEGIN
+		VALUE "Translation", 0x409, 1200
+	END
+END

+ 1779 - 0
compat/libusb-1.0/libusb/libusb.h

@@ -0,0 +1,1779 @@
+/*
+ * Public libusb header file
+ * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ * Copyright (C) 2012-2013 Nathan Hjelm <hjelmn@cs.unm.edu>
+ * Copyright (C) 2012 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_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;
+typedef unsigned __int32  uint32_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,
+
+	/** Physical */
+	LIBUSB_CLASS_PHYSICAL = 5,
+
+	/** Printer class */
+	LIBUSB_CLASS_PRINTER = 7,
+
+	/** Image class */
+	LIBUSB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */
+	LIBUSB_CLASS_IMAGE = 6,
+
+	/** Mass storage class */
+	LIBUSB_CLASS_MASS_STORAGE = 8,
+
+	/** Hub class */
+	LIBUSB_CLASS_HUB = 9,
+
+	/** Data class */
+	LIBUSB_CLASS_DATA = 10,
+
+	/** Smart Card */
+	LIBUSB_CLASS_SMART_CARD = 0x0b,
+
+	/** Content Security */
+	LIBUSB_CLASS_CONTENT_SECURITY = 0x0d,
+
+	/** Video */
+	LIBUSB_CLASS_VIDEO = 0x0e,
+
+	/** Personal Healthcare */
+	LIBUSB_CLASS_PERSONAL_HEALTHCARE = 0x0f,
+
+	/** Diagnostic Device */
+	LIBUSB_CLASS_DIAGNOSTIC_DEVICE = 0xdc,
+
+	/** 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,
+
+	/** BOS descriptor */
+	LIBUSB_DT_BOS = 0x0f,
+
+	/** Device Capability descriptor */
+	LIBUSB_DT_DEVICE_CAPABILITY = 0x10,
+
+	/** SuperSpeed Endpoint Companion descriptor */
+	LIBUSB_DT_SS_ENDPOINT_COMPANION = 0x30
+};
+
+/* 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_DT_SS_ENDPOINT_COMPANION_SIZE    6
+#define LIBUSB_DT_BOS_SIZE			5
+#define LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE	7
+#define LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE	10
+#define LIBUSB_DT_BOS_MAX_SIZE		((LIBUSB_DT_BOS_SIZE) + \
+					(LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE) + \
+					(LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE))
+
+#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 superspeed endpoint companion
+ * descriptor. This descriptor is documented in section 9.6.7 of
+ * the USB 3.0 specification. All ultiple-byte fields are represented in
+ * host-endian format.
+ */
+struct libusb_ss_endpoint_companion_descriptor {
+
+	/** Size of this descriptor (in bytes) */
+	uint8_t  bLength;
+
+	/** Descriptor type. Will have value
+	 * \ref libusb_descriptor_type::LIBUSB_DT_SS_ENDPOINT_COMPANION in
+	 * this context. */
+	uint8_t  bDescriptorType;
+
+
+	/** The maximum number of packets the endpoint can send or
+	 *  recieve as part of a burst. */
+	uint8_t  bMaxBurst;
+
+	/** In bulk EP:	bits 4:0 represents the	maximum	number of
+	 *  streams the	EP supports. In	isochronous EP:	bits 1:0
+	 *  represents the Mult	- a zero based value that determines
+	 *  the	maximum	number of packets within a service interval  */
+	uint8_t  bmAttributes;
+
+	/** The	total number of bytes this EP will transfer every
+	 *  service interval. valid only for periodic EPs. */
+	uint16_t wBytesPerInterval;
+};
+
+/** \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 desc
+ * A structure representing the BOS descriptor. This
+ * descriptor is documented in section 9.6.2 of the USB 3.0
+ * specification. All multiple-byte fields are represented in
+ * host-endian format.
+ */
+struct libusb_bos_descriptor {
+	/** Size of this descriptor (in bytes) */
+	uint8_t  bLength;
+
+	/** Descriptor type. Will have value
+	 * \ref libusb_descriptor_type::LIBUSB_DT_BOS LIBUSB_DT_BOS
+	 * in this context. */
+	uint8_t  bDescriptorType;
+
+	/** Length of this descriptor and all of its sub descriptors */
+	uint16_t wTotalLength;
+
+	/** The number of separate device capability descriptors in
+	 * the BOS */
+	uint8_t  bNumDeviceCaps;
+
+	/** USB 2.0 extension capability descriptor */
+	struct libusb_usb_2_0_device_capability_descriptor *usb_2_0_ext_cap;
+
+	/** SuperSpeed capabilty descriptor */
+	struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap;
+};
+
+/** \ingroup desc
+ * A structure representing the device capability descriptor for
+ * USB 2.0. This descriptor is documented in section 9.6.2.1 of
+ * the USB 3.0 specification. All mutiple-byte fields are represented
+ * in host-endian format.
+ */
+struct libusb_usb_2_0_device_capability_descriptor {
+	/** Size of this descriptor (in bytes) */
+	uint8_t  bLength;
+
+	/** Descriptor type. Will have value
+	 * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
+	 * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
+	uint8_t  bDescriptorType;
+
+	/** Capability type. Will have value
+	 * \ref libusb_capability_type::LIBUSB_USB_CAP_TYPE_EXT
+	 * LIBUSB_USB_CAP_TYPE_EXT in this context. */
+	uint8_t  bDevCapabilityType;
+
+	/** Bitmap encoding of supported device level features.
+	 * A value of one in a bit location indicates a feature is
+	 * supported; a value of zero indicates it is not supported.
+	 * See \ref libusb_capability_attributes. */
+	uint32_t  bmAttributes;
+};
+
+/** \ingroup desc
+ * A structure representing the device capability descriptor for
+ * USB 3.0. This descriptor is documented in section 9.6.2.2 of
+ * the USB 3.0 specification. All mutiple-byte fields are represented
+ * in host-endian format.
+ */
+struct libusb_ss_usb_device_capability_descriptor {
+	/** Size of this descriptor (in bytes) */
+	uint8_t  bLength;
+
+	/** Descriptor type. Will have value
+	 * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
+	 * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
+	uint8_t  bDescriptorType;
+
+	/** Capability type. Will have value
+	 * \ref libusb_capability_type::LIBUSB_SS_USB_CAP_TYPE
+	 * LIBUSB_SS_USB_CAP_TYPE in this context. */
+	uint8_t  bDevCapabilityType;
+
+	/** Bitmap encoding of supported device level features.
+	 * A value of one in a bit location indicates a feature is
+	 * supported; a value of zero indicates it is not supported.
+	 * See \ref libusb_capability_attributes. */
+	uint8_t  bmAttributes;
+
+	/** Bitmap encoding of the speed supported by this device when
+	 * operating in SuperSpeed mode. See \ref libusb_supported_speed. */
+	uint16_t wSpeedSupported;
+
+	/** The lowest speed at which all the functionality supported
+	 * by the device is available to the user. For example if the
+	 * device supports all its functionality when connected at
+	 * full speed and above then it sets this value to 1. */
+	uint8_t  bFunctionalitySupport;
+
+	/** U1 Device Exit Latency. */
+	uint8_t  bU1DevExitLat;
+
+	/** U2 Device Exit Latency. */
+	uint16_t bU2DevExitLat;
+};
+
+
+/** \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;
+struct libusb_hotplug_callback;
+
+/** \ingroup lib
+ * Structure representing the libusb version.
+ */
+struct libusb_version {
+	/** Library major version. */
+	const uint16_t major;
+
+	/** Library minor version. */
+	const uint16_t minor;
+
+	/** Library micro version. */
+	const uint16_t micro;
+
+	/** Library nano version. This field is only nonzero on Windows. */
+	const uint16_t nano;
+
+	/** Library release candidate suffix string, e.g. "-rc4". */
+	const char *rc;
+
+	/** Output of `git describe --tags` at library build time. */
+	const char *describe;
+};
+
+/** \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_ref_device() and
+ * libusb_unref_device(), 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 dev
+ * Speed codes. Indicates the speed at which the device is operating.
+ */
+enum libusb_speed {
+    /** The OS doesn't report or know the device speed. */
+    LIBUSB_SPEED_UNKNOWN = 0,
+
+    /** The device is operating at low speed (1.5MBit/s). */
+    LIBUSB_SPEED_LOW = 1,
+
+    /** The device is operating at full speed (12MBit/s). */
+    LIBUSB_SPEED_FULL = 2,
+
+    /** The device is operating at high speed (480MBit/s). */
+    LIBUSB_SPEED_HIGH = 3,
+
+    /** The device is operating at super speed (5000MBit/s). */
+    LIBUSB_SPEED_SUPER = 4,
+};
+
+/** \ingroup dev
+ * Supported speeds (wSpeedSupported) bitfield. Indicates what
+ * speeds the device supports.
+ */
+enum libusb_supported_speed {
+	/** Low speed operation supported (1.5MBit/s). */
+	LIBUSB_LOW_SPEED_OPERATION  = 1,
+
+	/** Full speed operation supported (12MBit/s). */
+	LIBUSB_FULL_SPEED_OPERATION = 2,
+
+	/** High speed operation supported (480MBit/s). */
+	LIBUSB_HIGH_SPEED_OPERATION = 4,
+
+	/** Superspeed operation supported (5000MBit/s). */
+	LIBUSB_5GBPS_OPERATION      = 8,
+};
+
+/** \ingroup dev
+ * Capability attributes
+ */
+enum libusb_capability_attributes {
+	/** Supports Link Power Management (LPM) */
+	LIBUSB_LPM_SUPPORT = 2,
+};
+
+/** \ingroup dev
+ * USB capability types
+ */
+enum libusb_capability_type {
+	/** USB 2.0 extension capability type */
+	LIBUSB_USB_CAP_TYPE_EXT = 2,
+
+	/** SuperSpeed capability type */
+	LIBUSB_SS_USB_CAP_TYPE  = 3,
+};
+
+/** \ingroup misc
+ * Error codes. Most libusb functions return 0 on success or one of these
+ * codes on failure.
+ * You can call \ref libusb_error_name() to retrieve a string representation
+ * of an error code or \ret libusb_strerror() to get an english description
+ * of an error code.
+ */
+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,
+
+	/* NB! Remember to update libusb_error_name() and
+	   libusb_strerror() when adding new error codes here. */
+
+	/** Other error */
+	LIBUSB_ERROR_OTHER = -99,
+};
+
+/** \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,
+
+	/** Terminate transfers that are a multiple of the endpoint's
+	 * wMaxPacketSize with an extra zero length packet. This is useful
+	 * when a device protocol mandates that each logical request is
+	 * terminated by an incomplete packet (i.e. the logical requests are
+	 * not separated by other means).
+	 *
+	 * This flag only affects host-to-device transfers to bulk and interrupt
+	 * endpoints. In other situations, it is ignored.
+	 *
+	 * This flag only affects transfers with a length that is a multiple of
+	 * the endpoint's wMaxPacketSize. On transfers of other lengths, this
+	 * flag has no effect. Therefore, if you are working with a device that
+	 * needs a ZLP whenever the end of the logical request falls on a packet
+	 * boundary, then it is sensible to set this flag on <em>every</em>
+	 * transfer (you do not have to worry about only setting it on transfers
+	 * that end on the boundary).
+	 *
+	 * This flag is currently only supported on Linux.
+	 * On other systems, libusb_submit_transfer() will return
+	 * LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set.
+	 *
+	 * Available since libusb-1.0.9.
+	 */
+	LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3,
+};
+
+/** \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
+	;
+};
+
+/** \ingroup misc
+ * Capabilities supported by this instance of libusb. Test if the loaded
+ * library supports a given capability by calling
+ * \ref libusb_has_capability().
+ */
+enum libusb_capability {
+	/** The libusb_has_capability() API is available. */
+	LIBUSB_CAP_HAS_CAPABILITY = 0,
+	/** The libusb hotplug API is available. */
+	LIBUSB_CAP_HAS_HOTPLUG    = 1,
+};
+
+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 struct libusb_version * LIBUSB_CALL libusb_get_version(void);
+int LIBUSB_CALL libusb_has_capability(uint32_t capability);
+const char * LIBUSB_CALL libusb_error_name(int errcode);
+const char * LIBUSB_CALL libusb_strerror(enum libusb_error errcode);
+
+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_device_speed(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, (uint16_t)((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_completed(libusb_context *ctx,
+	struct timeval *tv, int *completed);
+int LIBUSB_CALL libusb_handle_events(libusb_context *ctx);
+int LIBUSB_CALL libusb_handle_events_completed(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);
+
+/** \ingroup desc
+ * Parse a USB 3.0 endpoint companion descriptor.
+ *
+ * \param[in] buf the buffer containing the endpoint companion descriptor
+ * \param[in] len the length of the buffer
+ * \param[out] ep_comp a parsed endpoint companion descriptor. must be freed by
+ * libusb_free_ss_endpoint_comp()
+ *
+ * \returns LIBUSB_SUCCESS on success
+ * \returns LIBUSB_ERROR code on error
+ */
+int LIBUSB_CALL libusb_parse_ss_endpoint_comp(const void *buf, int len,
+					      struct libusb_ss_endpoint_companion_descriptor **ep_comp);
+
+/** \ingroup desc
+ * Free a USB 3.0 endpoint companion descriptor.
+ *
+ * \param[in] ep_comp the descriptor to free
+ */
+void LIBUSB_CALL libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp);
+
+/** \ingroup desc
+ * Parse a Binary Object Store (BOS) descriptor.
+ *
+ * \param[in] buf the buffer containing the BOS descriptor
+ * \param[in] len the length of the buffer
+ * \param[out] bos a parsed BOS descriptor. must be freed by
+ * libusb_free_bos_descriptor()
+ *
+ * \returns LIBUSB_SUCCESS on success
+ * \returns LIBUSB_ERROR code on error
+ */
+int LIBUSB_CALL libusb_parse_bos_descriptor(const void *buf, int len,
+					    struct libusb_bos_descriptor **bos);
+
+/** \ingroup desc
+ * Free a Binary Object Store (BOS) descriptor.
+ *
+ * \param[in] bos the descriptor to free
+ */
+void LIBUSB_CALL libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos);
+
+/** \ingroup hotplug
+ * Callback handle.
+ *
+ * Callbacks handles are generated by libusb_hotplug_register_callback()
+ * and can be used to deregister callbacks. Callback handles are unique
+ * per libusb_context and it is safe to call libusb_hotplug_deregister_callback()
+ * on an already deregisted callback.
+ *
+ * For more information, see \ref hotplug.
+ */
+typedef int libusb_hotplug_callback_handle;
+
+/** \ingroup hotplug
+ * Flags for hotplug events */
+typedef enum {
+	/** Arm the callback and fire it for all matching currently attached devices. */
+	LIBUSB_HOTPLUG_ENUMERATE = 1,
+} libusb_hotplug_flag;
+
+/** \ingroup hotplug
+ * Hotplug events */
+typedef enum {
+	/** A device has been plugged in and is ready to use */
+	LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = 0x01,
+
+	/** A device has left and is no longer available.
+	 * It is the user's responsibility to call libusb_close on any handle associated with a disconnected device.
+	 * It is safe to call libusb_get_device_descriptor on a device that has left */
+	LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT    = 0x02,
+} libusb_hotplug_event;
+
+/** \ingroup hotplug
+ * Wildcard matching for hotplug events */
+#define LIBUSB_HOTPLUG_MATCH_ANY -1
+
+/** \ingroup hotplug
+ * Hotplug callback function type. When requesting hotplug event notifications,
+ * you pass a pointer to a callback function of this type.
+ *
+ * This callback may be called by an internal event thread and as such it is
+ * recommended the callback do minimal processing before returning.
+ *
+ * libusb will call this function later, when a matching event had happened on
+ * a matching device. See \ref hotplug for more information.
+ *
+ * It is safe to call either libusb_hotplug_register_callback() or
+ * libusb_hotplug_deregister_callback() from within a callback function.
+ *
+ * \param libusb_context context of this notification
+ * \param device         libusb_device this event occurred on
+ * \param event          event that occurred
+ * \param user_data      user data provided when this callback was registered
+ * \returns bool whether this callback is finished processing events.
+ *                       returning 1 will cause this callback to be deregistered
+ */
+typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx,
+						      libusb_device *device,
+						      libusb_hotplug_event event,
+						      void *user_data);
+
+/** \ingroup hotplug
+ * Register a hotplug callback function
+ *
+ * Register a callback with the libusb_context. The callback will fire
+ * when a matching event occurs on a matching device. The callback is
+ * armed until either it is deregistered with libusb_hotplug_deregister_callback()
+ * or the supplied callback returns 1 to indicate it is finished processing events.
+ *
+ * \param[in] ctx context to register this callback with
+ * \param[in] events bitwise or of events that will trigger this callback. See \ref
+ *            libusb_hotplug_event
+ * \param[in] flags hotplug callback flags. See \ref libusb_hotplug_flag
+ * \param[in] vendor_id the vendor id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
+ * \param[in] product_id the product id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
+ * \param[in] dev_class the device class to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
+ * \param[in] cb_fn the function to be invoked on a matching event/device
+ * \param[in] user_data user data to pass to the callback function
+ * \param[out] handle pointer to store the handle of the allocated callback (can be NULL)
+ * \returns LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure
+ */
+int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx,
+						 libusb_hotplug_event events,
+						 libusb_hotplug_flag flags,
+						 int vendor_id, int product_id,
+						 int dev_class,
+						 libusb_hotplug_callback_fn cb_fn,
+						 void *user_data,
+						 libusb_hotplug_callback_handle *handle);
+
+/** \ingroup hotplug
+ * Deregisters a hotplug callback.
+ *
+ * Deregister a callback from a libusb_context. This function is safe to call from within
+ * a hotplug callback.
+ *
+ * \param[in] ctx context this callback is registered with
+ * \param[in] handle the handle of the callback to deregister
+ */
+void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx,
+						    libusb_hotplug_callback_handle handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 974 - 0
compat/libusb-1.0/libusb/libusbi.h

@@ -0,0 +1,974 @@
+/*
+ * 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 <stdarg.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+
+#include <libusb.h>
+#include <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, ...);
+
+void usbi_log_v(struct libusb_context *ctx, enum usbi_log_level level,
+	const char *function, const char *format, va_list args);
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1400
+
+#ifdef ENABLE_LOGGING
+#define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__)
+#else
+#define _usbi_log(ctx, level, ...) do { (void)(ctx); } while(0)
+#endif
+
+#ifdef ENABLE_DEBUG_LOGGING
+#define usbi_dbg(...) _usbi_log(NULL, LOG_LEVEL_DEBUG, __VA_ARGS__)
+#else
+#define usbi_dbg(...) do {} while(0)
+#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 >= 1400 */
+
+/* Old MS compilers don't support variadic macros. The code is simple, so we
+ * repeat it for each loglevel. Note that the debug case is special.
+ *
+ * Support for variadic macros was introduced in Visual C++ 2005.
+ * http://msdn.microsoft.com/en-us/library/ms177415%28v=VS.80%29.aspx
+ */
+
+static inline void usbi_info(struct libusb_context *ctx, const char *fmt, ...)
+{
+#ifdef ENABLE_LOGGING
+	va_list args;
+	va_start(args, fmt);
+	usbi_log_v(ctx, LOG_LEVEL_INFO, "", fmt, args);
+	va_end(args);
+#else
+	(void)ctx;
+#endif
+}
+
+static inline void usbi_warn(struct libusb_context *ctx, const char *fmt, ...)
+{
+#ifdef ENABLE_LOGGING
+	va_list args;
+	va_start(args, fmt);
+	usbi_log_v(ctx, LOG_LEVEL_WARNING, "", fmt, args);
+	va_end(args);
+#else
+	(void)ctx;
+#endif
+}
+
+static inline void usbi_err(struct libusb_context *ctx, const char *fmt, ...)
+{
+#ifdef ENABLE_LOGGING
+	va_list args;
+	va_start(args, fmt);
+	usbi_log_v(ctx, LOG_LEVEL_ERROR, "", fmt, args);
+	va_end(args);
+#else
+	(void)ctx;
+#endif
+}
+
+static inline void usbi_dbg(const char *fmt, ...)
+{
+#ifdef ENABLE_DEBUG_LOGGING
+	va_list args;
+	va_start(args, fmt);
+	usbi_log_v(NULL, LOG_LEVEL_DEBUG, "", fmt, args);
+	va_end(args);
+#else
+	(void)fmt;
+#endif
+}
+
+#endif /* !defined(_MSC_VER) || _MSC_VER >= 1400 */
+
+#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)))
+
+#define IS_EPIN(ep) (0 != ((ep) & LIBUSB_ENDPOINT_IN))
+#define IS_EPOUT(ep) (!IS_EPIN(ep))
+#define IS_XFERIN(xfer) (0 != ((xfer)->endpoint & LIBUSB_ENDPOINT_IN))
+#define IS_XFEROUT(xfer) (!IS_XFERIN(xfer))
+
+/* 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) || defined(OS_OPENBSD)
+#include <unistd.h>
+#include <os/poll_posix.h>
+#elif defined(OS_WINDOWS)
+#include <os/poll_windows.h>
+#endif
+
+#if defined(OS_WINDOWS) && !defined(__GCC__)
+#undef HAVE_GETTIMEOFDAY
+int usbi_gettimeofday(struct timeval *tp, void *tzp);
+#define LIBUSB_GETTIMEOFDAY_WIN32
+#define HAVE_USBI_GETTIMEOFDAY
+#else
+#ifdef HAVE_GETTIMEOFDAY
+#define usbi_gettimeofday(tv, tz) gettimeofday((tv), (tz))
+#define HAVE_USBI_GETTIMEOFDAY
+#endif
+#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;
+
+	/* A list of registered hotplug callbacks */
+	struct list_head hotplug_cbs;
+	usbi_mutex_t hotplug_cbs_lock;
+        int hotplug_pipe[2];
+
+	/* 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
+
+        struct list_head list;
+};
+
+#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;
+	enum libusb_speed speed;
+
+	struct list_head list;
+	unsigned long session_data;
+
+	struct libusb_device_descriptor device_descriptor;
+	int attached;
+
+	unsigned char os_priv
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+	[] /* valid C99 code */
+#else
+	[0] /* non-standard, but usually working code */
+#endif
+    ;
+};
+
+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
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+	[] /* valid C99 code */
+#else
+	[0] /* non-standard, but usually working code */
+#endif
+    ;
+};
+
+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;
+};
+
+enum usbi_transfer_flags {
+	/* The transfer has timed out */
+	USBI_TRANSFER_TIMED_OUT = 1 << 0,
+
+	/* Set by backend submit_transfer() if the OS handles timeout */
+	USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 1,
+
+	/* Cancellation was requested via libusb_cancel_transfer() */
+	USBI_TRANSFER_CANCELLING = 1 << 2,
+
+	/* Operation on the transfer failed because the device disappeared */
+	USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3,
+
+	/* Set by backend submit_transfer() if the fds in use were updated */
+	USBI_TRANSFER_UPDATED_FDS = 1 << 4,
+};
+
+#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(const unsigned char *source, const char *descriptor,
+	void *dest, int host_endian);
+int usbi_device_cache_descriptor(libusb_device *dev);
+int usbi_get_config_index_by_value(struct libusb_device *dev,
+	uint8_t bConfigurationValue, int *idx);
+
+void usbi_connect_device (struct libusb_device *dev);
+void usbi_disconnect_device (struct libusb_device *dev);
+
+/* 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
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+	[] /* valid C99 code */
+#else
+	[0] /* non-standard, but usually working code */
+#endif
+    ;
+};
+
+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, POLL_NFDS_TYPE 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 openbsd_backend;
+extern const struct usbi_os_backend windows_backend;
+
+extern struct list_head active_contexts_list;
+extern usbi_mutex_static_t active_contexts_lock;
+
+#endif
+

+ 1788 - 0
compat/libusb-1.0/libusb/os/darwin_usb.c

@@ -0,0 +1,1788 @@
+/* -*- Mode: C; indent-tabs-mode:nil -*- */
+/*
+ * darwin backend for libusb 1.0
+ * Copyright (C) 2008-2013 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 <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libkern/OSAtomic.h>
+
+#include <mach/clock.h>
+#include <mach/clock_types.h>
+#include <mach/mach_host.h>
+#include <mach/mach_port.h>
+
+#include <AvailabilityMacros.h>
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+  #include <objc/objc-auto.h>
+#endif
+
+#include "darwin_usb.h"
+
+/* async event thread */
+static pthread_mutex_t libusb_darwin_at_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t  libusb_darwin_at_cond = PTHREAD_COND_INITIALIZER;
+
+static clock_serv_t clock_realtime;
+static clock_serv_t clock_monotonic;
+
+static CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */
+static volatile int32_t 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 int darwin_scan_devices(struct libusb_context *ctx);
+static int process_new_device (struct libusb_context *ctx, usb_device_t **device, UInt32 locationID);
+
+#if defined(ENABLE_LOGGING)
+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";
+  case kIOReturnNoResources:
+    return "out of resources";
+  default:
+    return "unknown error";
+  }
+}
+#endif
+
+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, UInt32 location) {
+  CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
+
+  if (!matchingDict)
+    return kIOReturnError;
+
+  if (location) {
+    CFMutableDictionaryRef propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                                                         &kCFTypeDictionaryKeyCallBacks,
+                                                                         &kCFTypeDictionaryValueCallBacks);
+
+    if (propertyMatchDict) {
+      /* there are no unsigned CFNumber types so treat the value as signed. the os seems to do this
+         internally (CFNumberType of locationID is 3) */
+      CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberSInt32Type, &location);
+
+      CFDictionarySetValue (propertyMatchDict, CFSTR(kUSBDevicePropertyLocationID), locationCF);
+      /* release our reference to the CFNumber (CFDictionarySetValue retains it) */
+      CFRelease (locationCF);
+
+      CFDictionarySetValue (matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
+      /* release out reference to the CFMutableDictionaryRef (CFDictionarySetValue retains it) */
+      CFRelease (propertyMatchDict);
+    }
+    /* else we can still proceed as long as the caller accounts for the possibility of other devices in the iterator */
+  }
+
+  return IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, 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);
+
+    /* we are done with the usb_device_t */
+    (void)IOObjectRelease(usbDevice);
+    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)(*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID),
+                                           (LPVOID)&device);
+  /* Use release instead of IODestroyPlugInInterface to avoid stopping IOServices associated with this device */
+  (*plugInInterface)->Release (plugInInterface);
+
+  /* get the location from the device */
+  if (locationp)
+    (*(device))->GetLocationID(device, locationp);
+
+  return device;
+}
+
+static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) {
+  struct libusb_context *ctx;
+  usb_device_t **device;
+  UInt32 location;
+
+  usbi_mutex_lock(&active_contexts_lock);
+
+  while ((device = usb_get_next_device (add_devices, &location))) {
+    /* add this device to each active context's device list */
+    list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+      process_new_device (ctx, device, location);
+    }
+
+    /* release extra reference */
+    (*device)->Release (device);
+  }
+
+  usbi_mutex_unlock(&active_contexts_lock);
+}
+
+static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
+  struct libusb_device *dev = NULL;
+  struct libusb_context *ctx;
+
+  io_service_t device;
+  bool locationValid;
+  UInt32 location;
+  CFTypeRef locationCF;
+
+  while ((device = IOIteratorNext (rem_devices)) != 0) {
+    /* get the location from the i/o registry */
+    locationCF = IORegistryEntryCreateCFProperty (device, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault, 0);
+
+    IOObjectRelease (device);
+
+    if (!locationCF)
+      continue;
+
+    locationValid = CFGetTypeID(locationCF) == CFNumberGetTypeID() &&
+            CFNumberGetValue(locationCF, kCFNumberSInt32Type, &location);
+
+    CFRelease (locationCF);
+
+    if (!locationValid)
+      continue;
+
+    usbi_mutex_lock(&active_contexts_lock);
+
+    list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+      usbi_dbg ("libusb/darwin.c darwin_devices_detached: notifying context %p of device disconnect", ctx);
+
+      dev = usbi_get_device_by_session_id (ctx, location);
+      if (!dev) {
+        continue;
+      }
+
+      /* signal the core that this device has been disconnected. the core will tear down this device
+         when the reference count reaches 0 */
+      usbi_disconnect_device (dev);
+    }
+
+    usbi_mutex_unlock(&active_contexts_lock);
+  }
+}
+
+static void darwin_clear_iterator (io_iterator_t iter) {
+  io_service_t device;
+
+  while ((device = IOIteratorNext (iter)) != 0)
+    IOObjectRelease (device);
+}
+
+static void *darwin_event_thread_main (void *arg0) {
+  IOReturn kresult;
+  struct libusb_context *ctx = (struct libusb_context *)arg0;
+  CFRunLoopRef runloop;
+
+  /* Set this thread's name, so it can be seen in the debugger
+     and crash reports. */
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+  pthread_setname_np ("org.libusb.device-hotplug");
+#endif
+
+  /* Tell the Objective-C garbage collector about this thread.
+     This is required because, unlike NSThreads, pthreads are
+     not automatically registered. Although we don't use
+     Objective-C, we use CoreFoundation, which does. */
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+  objc_registerThreadWithCollector();
+#endif
+
+  /* hotplug (device arrival/removal) sources */
+  CFRunLoopSourceRef     libusb_notification_cfsource;
+  io_notification_port_t libusb_notification_port;
+  io_iterator_t          libusb_rem_device_iterator;
+  io_iterator_t          libusb_add_device_iterator;
+
+  usbi_info (ctx, "creating hotplug event source");
+
+  runloop = CFRunLoopGetCurrent ();
+  CFRetain (runloop);
+
+  /* add the notification port to the run loop */
+  libusb_notification_port     = IONotificationPortCreate (kIOMasterPortDefault);
+  libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port);
+  CFRunLoopAddSource(runloop, 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 (NULL);
+  }
+
+  /* create notifications for attached devices */
+  kresult = IOServiceAddMatchingNotification (libusb_notification_port, kIOFirstMatchNotification,
+                                              IOServiceMatching(kIOUSBDeviceClassName),
+                                              (IOServiceMatchingCallback)darwin_devices_attached,
+                                              (void *)ctx, &libusb_add_device_iterator);
+
+  if (kresult != kIOReturnSuccess) {
+    usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult));
+
+    pthread_exit (NULL);
+  }
+
+  /* arm notifiers */
+  darwin_clear_iterator (libusb_rem_device_iterator);
+  darwin_clear_iterator (libusb_add_device_iterator);
+
+  usbi_info (ctx, "darwin event thread ready to receive events");
+
+  /* signal the main thread that the hotplug runloop has been created. */
+  pthread_mutex_lock (&libusb_darwin_at_mutex);
+  libusb_darwin_acfl = runloop;
+  pthread_cond_signal (&libusb_darwin_at_cond);
+  pthread_mutex_unlock (&libusb_darwin_at_mutex);
+
+  /* run the runloop */
+  CFRunLoopRun();
+
+  usbi_info (ctx, "darwin event thread exiting");
+
+  /* remove the notification cfsource */
+  CFRunLoopRemoveSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode);
+
+  /* delete notification port */
+  IONotificationPortDestroy (libusb_notification_port);
+
+  /* delete iterators */
+  IOObjectRelease (libusb_rem_device_iterator);
+  IOObjectRelease (libusb_add_device_iterator);
+
+  CFRelease (runloop);
+
+  libusb_darwin_acfl = NULL;
+
+  pthread_exit (NULL);
+}
+
+static int darwin_init(struct libusb_context *ctx) {
+  host_name_port_t host_self;
+  int rc;
+
+  rc = darwin_scan_devices (ctx);
+  if (LIBUSB_SUCCESS != rc) {
+    return rc;
+  }
+
+  if (OSAtomicIncrement32Barrier(&initCount) == 1) {
+    /* create the clocks that will be used */
+
+    host_self = mach_host_self();
+    host_get_clock_service(host_self, CALENDAR_CLOCK, &clock_realtime);
+    host_get_clock_service(host_self, SYSTEM_CLOCK, &clock_monotonic);
+    mach_port_deallocate(mach_task_self(), host_self);
+
+    pthread_create (&libusb_darwin_at, NULL, darwin_event_thread_main, (void *)ctx);
+
+    pthread_mutex_lock (&libusb_darwin_at_mutex);
+    while (!libusb_darwin_acfl)
+      pthread_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex);
+    pthread_mutex_unlock (&libusb_darwin_at_mutex);
+  }
+
+  return 0;
+}
+
+static void darwin_exit (void) {
+  if (OSAtomicDecrement32Barrier(&initCount) == 0) {
+    mach_port_deallocate(mach_task_self(), clock_realtime);
+    mach_port_deallocate(mach_task_self(), clock_monotonic);
+
+    /* stop the event runloop and wait for the thread to terminate. */
+    CFRunLoopStop (libusb_darwin_acfl);
+    pthread_join (libusb_darwin_at, NULL);
+  }
+}
+
+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_NOT_FOUND;
+
+  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;
+
+  if (!priv || !priv->device)
+    return LIBUSB_ERROR_OTHER;
+
+  kresult = (*priv->device)->GetConfigurationDescriptorPtr (priv->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;
+  }
+
+  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 darwin_request_descriptor (usb_device_t **device, UInt8 desc, UInt8 desc_index, void *buffer, size_t buffer_size) {
+  IOUSBDevRequest req;
+
+  memset (buffer, 0, buffer_size);
+
+  /* Set up request for descriptor/ */
+  req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+  req.bRequest      = kUSBRqGetDescriptor;
+  req.wValue        = desc << 8;
+  req.wIndex        = desc_index;
+  req.wLength       = buffer_size;
+  req.pData         = buffer;
+
+  return (*device)->DeviceRequest (device, &req);
+}
+
+static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct libusb_device *dev, usb_device_t **device) {
+  struct darwin_device_priv *priv;
+  int retries = 2, delay = 30000;
+  int unsuspended = 0, try_unsuspend = 1, try_reconfigure = 1;
+  int is_open = 0;
+  int ret = 0, ret2;
+  UInt8 bDeviceClass;
+  UInt16 idProduct, idVendor;
+
+  (*device)->GetDeviceClass (device, &bDeviceClass);
+  (*device)->GetDeviceProduct (device, &idProduct);
+  (*device)->GetDeviceVendor (device, &idVendor);
+
+  priv = (struct darwin_device_priv *)dev->os_priv;
+
+  /* try to open the device (we can usually continue even if this fails) */
+  is_open = ((*device)->USBDeviceOpenSeize(device) == kIOReturnSuccess);
+
+  /**** retrieve device descriptor ****/
+  do {
+    /* according to Apple's documentation the device must be open for DeviceRequest but we may not be able to open some
+     * devices and Apple's USB Prober doesn't bother to open the device before issuing a descriptor request.  Still,
+     * to follow the spec as closely as possible, try opening the device */
+    ret = darwin_request_descriptor (device, kUSBDeviceDesc, 0, &priv->dev_descriptor, sizeof(priv->dev_descriptor));
+
+
+    if (kIOReturnOverrun == ret && kUSBDeviceDesc == priv->dev_descriptor.bDescriptorType)
+      /* received an overrun error but we still received a device descriptor */
+      ret = kIOReturnSuccess;
+
+    if (kIOUSBVendorIDAppleComputer == idVendor) {
+      /* NTH: don't bother retrying or unsuspending Apple devices */
+      break;
+    }
+
+    if (kIOReturnSuccess == ret && (0 == priv->dev_descriptor.bNumConfigurations ||
+                                    0 == priv->dev_descriptor.bcdUSB)) {
+      /* work around for incorrectly configured devices */
+      if (try_reconfigure && is_open) {
+        usbi_dbg("descriptor appears to be invalid. resetting configuration before trying again...");
+
+        /* set the first configuration */
+        (*device)->SetConfiguration(device, 1);
+
+        /* don't try to reconfigure again */
+        try_reconfigure = 0;
+      }
+
+      ret = kIOUSBPipeStalled;
+    }
+
+    if (kIOReturnSuccess != ret && is_open && try_unsuspend) {
+      /* device may be suspended. unsuspend it and try again */
+#if DeviceVersion >= 320
+      UInt32 info;
+
+      /* 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
+
+      if (try_unsuspend) {
+        /* resume the device */
+        ret2 = (*device)->USBDeviceSuspend (device, 0);
+        if (kIOReturnSuccess != ret2) {
+          /* prevent log spew from poorly behaving devices.  this indicates the
+             os actually had trouble communicating with the device */
+          usbi_dbg("could not retrieve device descriptor. failed to unsuspend: %s",darwin_error_str(ret2));
+        } else
+          unsuspended = 1;
+
+        try_unsuspend = 0;
+      }
+    }
+
+    if (kIOReturnSuccess != ret) {
+      usbi_dbg("kernel responded with code: 0x%08x. sleeping for %d ms before trying again", ret, delay/1000);
+      /* sleep for a little while before trying again */
+      usleep (delay);
+    }
+  } while (kIOReturnSuccess != ret && retries--);
+
+  if (unsuspended)
+    /* resuspend the device */
+    (void)(*device)->USBDeviceSuspend (device, 1);
+
+  if (is_open)
+    (void) (*device)->USBDeviceClose (device);
+
+  if (ret != kIOReturnSuccess) {
+    /* a debug message was already printed out for this error */
+    if (LIBUSB_CLASS_HUB == bDeviceClass)
+      usbi_dbg ("could not retrieve device descriptor %.4x:%.4x: %s. skipping device", idVendor, idProduct, darwin_error_str (ret));
+    else
+      usbi_warn (ctx, "could not retrieve device descriptor %.4x:%.4x: %s. skipping device", idVendor, idProduct, darwin_error_str (ret));
+
+    return -1;
+  }
+
+  usbi_dbg ("device descriptor:");
+  usbi_dbg (" bDescriptorType:    0x%02x", priv->dev_descriptor.bDescriptorType);
+  usbi_dbg (" bcdUSB:             0x%04x", priv->dev_descriptor.bcdUSB);
+  usbi_dbg (" bDeviceClass:       0x%02x", priv->dev_descriptor.bDeviceClass);
+  usbi_dbg (" bDeviceSubClass:    0x%02x", priv->dev_descriptor.bDeviceSubClass);
+  usbi_dbg (" bDeviceProtocol:    0x%02x", priv->dev_descriptor.bDeviceProtocol);
+  usbi_dbg (" bMaxPacketSize0:    0x%02x", priv->dev_descriptor.bMaxPacketSize0);
+  usbi_dbg (" idVendor:           0x%04x", priv->dev_descriptor.idVendor);
+  usbi_dbg (" idProduct:          0x%04x", priv->dev_descriptor.idProduct);
+  usbi_dbg (" bcdDevice:          0x%04x", priv->dev_descriptor.bcdDevice);
+  usbi_dbg (" iManufacturer:      0x%02x", priv->dev_descriptor.iManufacturer);
+  usbi_dbg (" iProduct:           0x%02x", priv->dev_descriptor.iProduct);
+  usbi_dbg (" iSerialNumber:      0x%02x", priv->dev_descriptor.iSerialNumber);
+  usbi_dbg (" bNumConfigurations: 0x%02x", priv->dev_descriptor.bNumConfigurations);
+
+  /* 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));
+    return -1;
+  }
+
+  return 0;
+}
+
+static int process_new_device (struct libusb_context *ctx, usb_device_t **device, UInt32 locationID) {
+  struct libusb_device *dev = NULL;
+  struct darwin_device_priv *priv;
+  UInt8 devSpeed;
+  UInt16 address;
+  int ret = 0;
+
+  do {
+    usbi_info (ctx, "allocating new device for location 0x%08x", locationID);
+
+    dev = usbi_alloc_device(ctx, locationID);
+    if (!dev) {
+      return LIBUSB_ERROR_NO_MEM;
+    }
+
+    priv = (struct darwin_device_priv *)dev->os_priv;
+    priv->device = device;
+
+    /* increment the device's reference count (it is decremented in darwin_destroy_device) */
+    (*device)->AddRef (device);
+
+    (*device)->GetDeviceAddress (device, (USBDeviceAddress *)&address);
+
+    ret = darwin_cache_device_descriptor (ctx, dev, device);
+    if (ret < 0)
+      break;
+
+    /* 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;
+
+    dev->bus_number     = locationID >> 24;
+    dev->device_address = address;
+
+    (*device)->GetDeviceSpeed (device, &devSpeed);
+
+    switch (devSpeed) {
+    case kUSBDeviceSpeedLow: dev->speed = LIBUSB_SPEED_LOW; break;
+    case kUSBDeviceSpeedFull: dev->speed = LIBUSB_SPEED_FULL; break;
+    case kUSBDeviceSpeedHigh: dev->speed = LIBUSB_SPEED_HIGH; break;
+#if DeviceVersion >= 500
+    case kUSBDeviceSpeedSuper: dev->speed = LIBUSB_SPEED_SUPER; break;
+#endif
+    default:
+      usbi_warn (ctx, "Got unknown device speed %d", devSpeed);
+    }
+
+    /* save our location, we'll need this later */
+    priv->location = locationID;
+    snprintf(priv->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", address, priv->dev_descriptor.idVendor, priv->dev_descriptor.idProduct,
+             priv->dev_descriptor.bDeviceClass, priv->dev_descriptor.bDeviceSubClass);
+
+    ret = usbi_sanitize_device (dev);
+    if (ret < 0)
+      break;
+
+    usbi_info (ctx, "found device with address %d at %s", dev->device_address, priv->sys_path);
+  } while (0);
+
+  if (0 == ret) {
+    usbi_connect_device (dev);
+  } else {
+    libusb_unref_device (dev);
+  }
+
+  return ret;
+}
+
+static int darwin_scan_devices(struct libusb_context *ctx) {
+  io_iterator_t        deviceIterator;
+  usb_device_t         **device;
+  kern_return_t        kresult;
+  UInt32               location;
+
+  kresult = usb_setup_device_iterator (&deviceIterator, 0);
+  if (kresult != kIOReturnSuccess)
+    return darwin_to_libusb (kresult);
+
+  while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
+    (void) process_new_device (ctx, device, location);
+
+    /* process_new_device added a reference so we need to release the one
+       from QueryInterface */
+    (*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;
+  IOReturn kresult;
+
+  if (0 == dpriv->open_count) {
+    /* 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));
+
+      if (kIOReturnExclusiveAccess != kresult) {
+        return darwin_to_libusb (kresult);
+      }
+
+      /* it is possible to perform some actions on a device that is not open so do not return an error */
+      priv->is_open = 0;
+    } else {
+      priv->is_open = 1;
+    }
+
+    /* create async event source */
+    kresult = (*(dpriv->device))->CreateDeviceAsyncEventSource (dpriv->device, &priv->cfSource);
+    if (kresult != kIOReturnSuccess) {
+      usbi_err (HANDLE_CTX (dev_handle), "CreateDeviceAsyncEventSource: %s", darwin_error_str(kresult));
+
+      if (priv->is_open) {
+        (*(dpriv->device))->USBDeviceClose (dpriv->device);
+      }
+
+      priv->is_open = 0;
+
+      return darwin_to_libusb (kresult);
+    }
+
+    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) {
+    /* delete the device's async event source */
+    if (priv->cfSource) {
+      CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode);
+      CFRelease (priv->cfSource);
+      priv->cfSource = NULL;
+      CFRelease (libusb_darwin_acfl);
+    }
+
+    if (priv->is_open) {
+      /* 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));
+      }
+    }
+  }
+
+  /* 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;
+  kern_return_t             kresult;
+  io_iterator_t             interface_iterator;
+  CFTypeRef                 bInterfaceNumberCF;
+  int                       bInterfaceNumber;
+
+  *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;
+
+  while ((*usbInterfacep = IOIteratorNext(interface_iterator))) {
+    /* find the interface number */
+    bInterfaceNumberCF = IORegistryEntryCreateCFProperty (*usbInterfacep, CFSTR("bInterfaceNumber"),
+                                                          kCFAllocatorDefault, 0);
+    if (!bInterfaceNumberCF) {
+      continue;
+    }
+
+    CFNumberGetValue(bInterfaceNumberCF, kCFNumberIntType, &bInterfaceNumber);
+
+    CFRelease(bInterfaceNumberCF);
+
+    if ((uint8_t) bInterfaceNumber == ifc) {
+      break;
+    }
+
+    (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);
+
+  /* ignore release error */
+  (void)IOObjectRelease (usbInterface);
+
+  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;
+  }
+
+  /* Do the actual claim */
+  kresult = (*plugInInterface)->QueryInterface(plugInInterface,
+                                               CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
+                                               (LPVOID)&cInterface->interface);
+  /* We no longer need the intermediate plug-in */
+  /* Use release instead of IODestroyPlugInInterface to avoid stopping IOServices associated with this device */
+  (*plugInInterface)->Release (plugInInterface);
+  if (kresult || !cInterface->interface) {
+    usbi_err (HANDLE_CTX (dev_handle), "QueryInterface: %s", darwin_error_str(kresult));
+    return darwin_to_libusb (kresult);
+  }
+
+  /* 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;
+  IOUSBDeviceDescriptor descriptor;
+  IOUSBConfigurationDescriptorPtr cached_configuration;
+  IOUSBConfigurationDescriptor configuration;
+  bool reenumerate = false;
+  IOReturn kresult;
+  int i;
+
+  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);
+  }
+
+  do {
+    usbi_dbg ("darwin/reset_device: checking if device descriptor changed");
+
+    /* ignore return code. if we can't get a descriptor it might be worthwhile re-enumerating anway */
+    (void) darwin_request_descriptor (dpriv->device, kUSBDeviceDesc, 0, &descriptor, sizeof (descriptor));
+
+    /* check if the device descriptor has changed */
+    if (0 != memcmp (&dpriv->dev_descriptor, &descriptor, sizeof (descriptor))) {
+      reenumerate = true;
+      break;
+    }
+
+    /* check if any configuration descriptor has changed */
+    for (i = 0 ; i < descriptor.bNumConfigurations ; ++i) {
+      usbi_dbg ("darwin/reset_device: checking if configuration descriptor %d changed", i);
+
+      (void) darwin_request_descriptor (dpriv->device, kUSBConfDesc, i, &configuration, sizeof (configuration));
+      (*(dpriv->device))->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
+
+      if (!cached_configuration || 0 != memcmp (cached_configuration, &configuration, sizeof (configuration))) {
+        reenumerate = true;
+        break;
+      }
+    }
+  } while (0);
+
+  if (reenumerate) {
+    usbi_dbg ("darwin/reset_device: device requires reenumeration");
+    (void) (*(dpriv->device))->USBDeviceReEnumerate (dpriv->device, 0);
+    return LIBUSB_ERROR_NOT_FOUND;
+  }
+
+  usbi_dbg ("darwin/reset_device: device reset complete");
+
+  return LIBUSB_SUCCESS;
+}
+
+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) {
+  (void)dev_handle;
+  (void)interface;
+  return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
+  (void)dev_handle;
+  (void)interface;
+  return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+static void darwin_destroy_device(struct libusb_device *dev) {
+  struct darwin_device_priv *dpriv = (struct darwin_device_priv *) dev->os_priv;
+
+  if (dpriv->device) {
+    /* it is an internal error if the reference count of a device is < 0 after release */
+    assert(0 <= (*(dpriv->device))->Release(dpriv->device));
+
+    dpriv->device = NULL;
+  }
+}
+
+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                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;
+
+  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);
+
+  if (0 != (transfer->length % maxPacketSize)) {
+    /* do not need a zero packet */
+    transfer->flags &= ~LIBUSB_TRANSFER_ADD_ZERO_PACKET;
+  }
+
+  /* submit the request */
+  /* timeouts are unavailable on interrupt endpoints */
+  if (transferType == kUSBInterrupt) {
+    if (IS_XFERIN(transfer))
+      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 {
+    itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
+
+    if (IS_XFERIN(transfer))
+      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_XFERIN(transfer) ? "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 direction, number, interval, pipeRef, iface, transferType;
+  uint16_t maxPacketSize;
+  UInt64 frame;
+  AbsoluteTime atTime;
+  int i;
+
+  struct darwin_interface *cInterface;
+
+  /* construct an array of IOUSBIsocFrames, reuse the old one if possible */
+  if (tpriv->isoc_framelist && tpriv->num_iso_packets != transfer->num_iso_packets) {
+    free(tpriv->isoc_framelist);
+    tpriv->isoc_framelist = NULL;
+  }
+
+  if (!tpriv->isoc_framelist) {
+    tpriv->num_iso_packets = transfer->num_iso_packets;
+    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];
+
+  /* determine the properties of this endpoint and the speed of the device */
+  (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
+                                                 &transferType, &maxPacketSize, &interval);
+
+  /* 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 += 4;
+
+  if (cInterface->frames[transfer->endpoint] && frame < cInterface->frames[transfer->endpoint])
+    frame = cInterface->frames[transfer->endpoint];
+
+  /* submit the request */
+  if (IS_XFERIN(transfer))
+    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 (LIBUSB_SPEED_FULL == transfer->dev_handle->dev->speed)
+    /* Full speed */
+    cInterface->frames[transfer->endpoint] = frame + transfer->num_iso_packets * (1 << (interval - 1));
+  else
+    /* High/super speed */
+    cInterface->frames[transfer->endpoint] = frame + transfer->num_iso_packets * (1 << (interval - 1)) / 8;
+
+  if (kresult != kIOReturnSuccess) {
+    usbi_err (TRANSFER_CTX (transfer), "isochronous transfer failed (dir: %s): %s", IS_XFERIN(transfer) ? "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_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->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;
+
+  itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
+
+  /* all transfers in libusb-1.0 are async */
+
+  if (transfer->endpoint) {
+    struct darwin_interface *cInterface;
+    uint8_t                 pipeRef, iface;
+
+    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];
+
+    kresult = (*(cInterface->interface))->ControlRequestAsyncTO (cInterface->interface, pipeRef, &(tpriv->req), darwin_async_io_callback, itransfer);
+  } else
+    /* control request on endpoint 0 */
+    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");
+
+  if (!dpriv->device)
+    return LIBUSB_ERROR_NO_DEVICE;
+
+  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_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv;
+  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];
+
+  if (!dpriv->device)
+    return LIBUSB_ERROR_NO_DEVICE;
+
+  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;
+  struct darwin_msg_async_io_complete message = {.itransfer = itransfer, .result = result,
+                                                 .size = (UInt32) (uintptr_t) arg0};
+
+  usbi_info (ITRANSFER_CTX (itransfer), "an async io operation has completed");
+
+  /* if requested write a zero packet */
+  if (kIOReturnSuccess == result && IS_XFEROUT(transfer) && transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
+    struct darwin_interface *cInterface;
+    uint8_t iface, pipeRef;
+
+    (void) ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface);
+    cInterface = &priv->interfaces[iface];
+
+    (*(cInterface->interface))->WritePipe (cInterface->interface, pipeRef, transfer->buffer, 0);
+  }
+
+  /* send a completion message to the device's file descriptor */
+  write (priv->fds[1], &message, sizeof (message));
+}
+
+static int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_t result) {
+  if (itransfer->flags & USBI_TRANSFER_TIMED_OUT)
+    result = kIOUSBTransactionTimeout;
+
+  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");
+    itransfer->flags |= USBI_TRANSFER_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, POLL_NFDS_TYPE nfds, int num_ready) {
+  struct darwin_msg_async_io_complete message;
+  POLL_NFDS_TYPE i = 0;
+  ssize_t ret;
+
+  usbi_mutex_lock(&ctx->open_devs_lock);
+
+  for (i = 0; i < nfds && num_ready > 0; i++) {
+    struct pollfd *pollfd = &fds[i];
+
+    usbi_info (ctx, "checking fd %i with revents = %x", pollfd->fd, pollfd->revents);
+
+    if (!pollfd->revents)
+      continue;
+
+    num_ready--;
+
+    if (pollfd->revents & POLLERR) {
+      /* this probably will never happen so ignore the error an move on. */
+      continue;
+    }
+
+    /* there is only one type of message */
+    ret = read (pollfd->fd, &message, sizeof (message));
+    if (ret < (ssize_t) sizeof (message)) {
+      usbi_dbg ("WARNING: short read on async io completion pipe\n");
+      continue;
+    }
+
+    darwin_handle_callback (message.itransfer, message.result, message.size);
+  }
+
+  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 */
+    clock_ref = clock_realtime;
+    break;
+  case USBI_CLOCK_MONOTONIC:
+    /* use system boot time as reference for the monotonic clock */
+    clock_ref = clock_monotonic;
+    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 = NULL, /* not needed */
+        .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,
+};
+

+ 175 - 0
compat/libusb-1.0/libusb/os/darwin_usb.h

@@ -0,0 +1,175 @@
+/*
+ * darwin backend for libusb 1.0
+ * Copyright (C) 2008-2013 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 (kIOUSBDeviceInterfaceID500)
+
+#define usb_device_t    IOUSBDeviceInterface500
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID500
+#define DeviceVersion 500
+
+#elif 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;
+    uint64_t             frames[256];
+    uint8_t            endpoint_addrs[USB_MAXENDPOINTS];
+  } interfaces[USB_MAXINTERFACES];
+};
+
+struct darwin_transfer_priv {
+  /* Isoc */
+  IOUSBIsocFrame *isoc_framelist;
+  int num_iso_packets;
+
+  /* Control */
+#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
+  IOUSBDevRequestTO req;
+#else
+  IOUSBDevRequest req;
+#endif
+
+  /* Bulk */
+};
+
+/* structure for signaling io completion */
+struct darwin_msg_async_io_complete {
+  struct usbi_transfer *itransfer;
+  IOReturn result;
+  UInt32 size;
+};
+
+#endif

+ 231 - 0
compat/libusb-1.0/libusb/os/linux_netlink.c

@@ -0,0 +1,231 @@
+/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */
+/*
+ * Linux usbfs backend for libusb
+ * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ * Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "libusb.h"
+#include "libusbi.h"
+#include "linux_usbfs.h"
+
+#include <linux/netlink.h>
+#include <linux/filter.h>
+
+#define KERNEL 1
+
+static int linux_netlink_socket = -1;
+static pthread_t libusb_linux_event_thread;
+
+static void *linux_netlink_event_thread_main(void *arg);
+
+struct sockaddr_nl snl = { .nl_family=AF_NETLINK, .nl_groups=KERNEL };
+
+int linux_netlink_start_event_monitor(void)
+{
+	int ret;
+
+	snl.nl_groups = KERNEL;
+
+	linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
+	if (-1 == linux_netlink_socket) {
+		return LIBUSB_ERROR_OTHER;
+	}
+
+	ret = bind(linux_netlink_socket, (struct sockaddr *) &snl, sizeof(snl));
+	if (0 != ret) {
+		return LIBUSB_ERROR_OTHER;
+	}
+
+	/* TODO -- add authentication */
+	/* setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); */
+
+	ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL);
+	if (0 != ret) {
+		return LIBUSB_ERROR_OTHER;
+	}
+
+	return LIBUSB_SUCCESS;
+}
+
+int linux_netlink_stop_event_monitor(void)
+{
+	int r;
+
+	if (-1 == linux_netlink_socket) {
+		/* already closed. nothing to do */
+		return LIBUSB_SUCCESS;
+	}
+
+	r = close(linux_netlink_socket);
+	if (0 > r) {
+		usbi_err(NULL, "error closing netlink socket. %s", strerror(errno));
+		return LIBUSB_ERROR_OTHER;
+	}
+
+	pthread_cancel(libusb_linux_event_thread);
+
+	linux_netlink_socket = -1;
+
+	return LIBUSB_SUCCESS;
+}
+
+static const char *netlink_message_parse (const char *buffer, size_t len, const char *key)
+{
+	size_t keylen = strlen(key);
+	size_t offset;
+
+	for (offset = 0 ; offset < len && '\0' != buffer[offset] ; offset += strlen(buffer + offset) + 1) {
+		if (0 == strncmp(buffer + offset, key, keylen) &&
+		    '=' == buffer[offset + keylen]) {
+			return buffer + offset + keylen + 1;
+		}
+	}
+
+	return NULL;
+}
+
+/* parse parts of netlink message common to both libudev and the kernel */
+static int linux_netlink_parse(char *buffer, size_t len, int *detached, const char **sys_name,
+			       uint8_t *busnum, uint8_t *devaddr) {
+	const char *tmp;
+	int i;
+
+	errno = 0;
+
+	*sys_name = NULL;
+	*detached = 0;
+	*busnum   = 0;
+	*devaddr  = 0;
+
+	tmp = netlink_message_parse((const char *) buffer, len, "ACTION");
+	if (0 == strcmp(tmp, "remove")) {
+		*detached = 1;
+	} else if (0 != strcmp(tmp, "add")) {
+		usbi_dbg("unknown device action");
+		return -1;
+	}
+
+	/* check that this is a usb message */
+	tmp = netlink_message_parse(buffer, len, "SUBSYSTEM");
+	if (NULL == tmp || 0 != strcmp(tmp, "usb")) {
+		/* not usb. ignore */
+		return -1;
+	}
+
+	tmp = netlink_message_parse(buffer, len, "BUSNUM");
+	if (NULL == tmp) {
+		/* no bus number (likely a usb interface). ignore*/
+		return -1;
+	}
+
+	*busnum = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff);
+	if (errno) {
+		errno = 0;
+		return -1;
+	}
+
+	tmp = netlink_message_parse(buffer, len, "DEVNUM");
+	if (NULL == tmp) {
+		return -1;
+	}
+
+	*devaddr = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff);
+	if (errno) {
+		errno = 0;
+		return -1;
+	}
+
+	tmp = netlink_message_parse(buffer, len, "DEVPATH");
+	if (NULL == tmp) {
+		return -1;
+	}
+
+	for (i = strlen(tmp) - 1 ; i ; --i) {
+		if ('/' ==tmp[i]) {
+			*sys_name = tmp + i + 1;
+			break;
+		}
+	}
+
+	/* found a usb device */
+	return 0;
+}
+
+static void *linux_netlink_event_thread_main(void *arg)
+{
+	struct pollfd fds = {.fd = linux_netlink_socket,
+			     .events = POLLIN};
+	unsigned char buffer[1024];
+	struct iovec iov = {.iov_base = buffer, .iov_len = sizeof(buffer)};
+	struct msghdr meh = { .msg_iov=&iov, .msg_iovlen=1,
+			     .msg_name=&snl, .msg_namelen=sizeof(snl) };
+	uint8_t busnum, devaddr;
+	int detached, r;
+	size_t len;
+
+	/* silence compiler warning */
+	(void) arg;
+
+	while (1 == poll(&fds, 1, -1)) {
+		const char *sys_name = NULL;
+
+		if (POLLIN != fds.revents) {
+			break;
+		}
+
+		/* read netlink message */
+		memset(buffer, 0, sizeof(buffer));
+		len = recvmsg(linux_netlink_socket, &meh, 0);
+		if (len < 32) {
+			usbi_dbg("error recieving message from netlink");
+			continue;
+		}
+
+		/* TODO -- authenticate this message is from the kernel or udevd */
+
+		r = linux_netlink_parse(buffer, len, &detached, &sys_name,
+					&busnum, &devaddr);
+		if (r)
+			continue;
+
+		usbi_dbg("netlink hotplug found device busnum: %hhu, devaddr: %hhu, sys_name: %s, removed: %s",
+			 busnum, devaddr, sys_name, detached ? "yes" : "no");
+
+		/* signal device is available (or not) to all contexts */
+		if (detached)
+			linux_hotplug_disconnected(busnum, devaddr, sys_name);
+		else
+			linux_hotplug_enumerate(busnum, devaddr, sys_name);
+	}
+
+	return NULL;	
+}

+ 242 - 0
compat/libusb-1.0/libusb/os/linux_udev.c

@@ -0,0 +1,242 @@
+/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */
+/*
+ * Linux usbfs backend for libusb
+ * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ * Copyright (c) 2012-2013 Nathan Hjelm <hjelmn@mac.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 <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 <sys/socket.h>
+#include <unistd.h>
+#include <libudev.h>
+
+#include "libusb.h"
+#include "libusbi.h"
+#include "linux_usbfs.h"
+
+/* udev context */
+static struct udev *udev_ctx = NULL;
+static int udev_monitor_fd = -1;
+static struct udev_monitor *udev_monitor = NULL;
+static pthread_t linux_event_thread;
+
+static void udev_hotplug_event(void);
+static void *linux_udev_event_thread_main(void *arg);
+
+int linux_udev_start_event_monitor(void)
+{
+	int r;
+
+	if (NULL == udev_ctx) {
+		udev_ctx = udev_new();
+		if (!udev_ctx) {
+			return LIBUSB_ERROR_OTHER;
+		}
+	}
+
+        udev_monitor = udev_monitor_new_from_netlink(udev_ctx, "udev");
+        if (!udev_monitor) {
+                usbi_err(NULL, "could not initialize udev monitor");
+                return LIBUSB_ERROR_OTHER;
+        }
+
+        r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", 0);
+        if (r) {
+                usbi_err(NULL, "could not initialize udev monitor filter for \"usb\" subsystem");
+                return LIBUSB_ERROR_OTHER;
+        }
+
+        if (udev_monitor_enable_receiving(udev_monitor)) {
+                usbi_err(NULL, "failed to enable the udev monitor");
+                return LIBUSB_ERROR_OTHER;
+        }
+
+        udev_monitor_fd = udev_monitor_get_fd(udev_monitor);
+
+        pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL);
+
+        return LIBUSB_SUCCESS;
+}
+
+int linux_udev_stop_event_monitor(void)
+{
+        if (-1 == udev_monitor_fd) {
+                /* this should never happen */
+                return LIBUSB_ERROR_OTHER;
+        }
+
+	/* Cancel the event thread. This is the only way to garauntee the thread
+	   exits since closing the monitor fd won't necessarily cause poll
+	   to return. */
+	pthread_cancel(linux_event_thread);
+
+	/* Release the udev monitor */
+        udev_monitor_unref(udev_monitor);
+	udev_monitor = NULL;
+        udev_monitor_fd = -1;
+
+	/* Clean up the udev context */
+	udev_unref(udev_ctx);
+	udev_ctx = NULL;
+
+        return LIBUSB_SUCCESS;
+}
+
+static void *linux_udev_event_thread_main(void *arg)
+{
+	struct pollfd fds = {.fd = udev_monitor_fd,
+			     .events = POLLIN};
+
+	usbi_dbg("udev event thread entering.");
+
+	while (1 == poll(&fds, 1, -1)) {
+		if (NULL == udev_monitor || POLLIN != fds.revents) {
+			break;
+		}
+
+		udev_hotplug_event();
+	}
+
+	usbi_dbg("udev event thread exiting");
+
+	return NULL;
+}
+
+static int udev_device_info(struct libusb_context *ctx, int detached,
+			    struct udev_device *udev_dev, uint8_t *busnum,
+			    uint8_t *devaddr, const char **sys_name) {
+	const char *dev_node;
+
+	dev_node = udev_device_get_devnode(udev_dev);
+	if (!dev_node) {
+		return LIBUSB_ERROR_OTHER;
+	}
+
+	*sys_name = udev_device_get_sysname(udev_dev);
+	if (!*sys_name) {
+		return LIBUSB_ERROR_OTHER;
+	}
+
+        return linux_get_device_address(ctx, detached, busnum, devaddr,
+					dev_node, *sys_name);
+}
+
+static void udev_hotplug_event(void)
+{
+	struct udev_device* udev_dev;
+	const char* udev_action;
+	const char* sys_name = NULL;
+	uint8_t busnum = 0, devaddr = 0;
+	int detached;
+	int r;
+
+	if (NULL == udev_monitor) {
+		return;
+	}
+
+	do {
+		udev_dev = udev_monitor_receive_device(udev_monitor);
+		if (!udev_dev) {
+			usbi_err(NULL, "failed to read data from udev monitor socket.");
+			return;
+		}
+
+		udev_action = udev_device_get_action(udev_dev);
+		if (!udev_action) {
+			break;
+		}
+
+		detached = !strncmp(udev_action, "remove", 6);
+
+		r = udev_device_info(NULL, detached, udev_dev, &busnum, &devaddr, &sys_name);
+		if (LIBUSB_SUCCESS != r) {
+			break;
+		}
+
+		usbi_dbg("udev hotplug event. action: %s.", udev_action);
+
+		if (strncmp(udev_action, "add", 3) == 0) {
+			linux_hotplug_enumerate(busnum, devaddr, sys_name);
+		} else if (detached) {
+			linux_hotplug_disconnected(busnum, devaddr, sys_name);
+		} else {
+			usbi_err(NULL, "ignoring udev action %s", udev_action);
+		}
+	} while (0);
+
+	udev_device_unref(udev_dev);
+}
+
+int linux_udev_scan_devices(struct libusb_context *ctx)
+{
+	struct udev_enumerate *enumerator;
+	struct udev_list_entry *devices, *entry;
+	struct udev_device *udev_dev;
+	const char *sys_name;
+	int r;
+
+	if (NULL == udev_ctx) {
+		udev_ctx = udev_new();
+		if (!udev_ctx) {
+			return LIBUSB_ERROR_OTHER;
+		}
+	}
+
+	enumerator = udev_enumerate_new(udev_ctx);
+	if (NULL == enumerator) {
+		usbi_err(ctx, "error creating udev enumerator");
+		return LIBUSB_ERROR_OTHER;
+	}
+
+	udev_enumerate_add_match_subsystem(enumerator, "usb");
+	udev_enumerate_scan_devices(enumerator);
+	devices = udev_enumerate_get_list_entry(enumerator);
+
+	udev_list_entry_foreach(entry, devices) {
+		const char *path = udev_list_entry_get_name(entry);
+		uint8_t busnum = 0, devaddr = 0;
+
+		udev_dev = udev_device_new_from_syspath(udev_ctx, path);
+
+		r = udev_device_info(ctx, 0, udev_dev, &busnum, &devaddr, &sys_name);
+		if (r) {
+			udev_device_unref(udev_dev);
+			continue;
+		}
+
+		linux_enumerate_device(ctx, busnum, devaddr, sys_name);
+		udev_device_unref(udev_dev);
+	}
+
+	udev_enumerate_unref(enumerator);
+
+        return LIBUSB_SUCCESS;
+}
+

+ 2605 - 0
compat/libusb-1.0/libusb/os/linux_usbfs.c

@@ -0,0 +1,2605 @@
+/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */
+/*
+ * Linux usbfs backend for libusb
+ * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ * Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.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 <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.
+ */
+
+const char *usbfs_path = NULL;
+
+/* use usbdev*.* device names in /dev instead of the usbfs bus directories */
+static int usbdev_names = 0;
+
+/* 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 except a cancellation, all
+ * URBs within that transfer will be cancelled and no more URBs will be
+ * accepted for the transfer, meaning that no more data can creep in.
+ *
+ * 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 URBs except the
+ * last; it means that the kernel should treat a short reply as an error.
+ * For OUT transfers, SHORT_NOT_OK must not be set. it isn't needed (OUT
+ * transfers can't be short unless there's already some sort of error), and
+ * setting this flag is disallowed (a kernel with USB debugging enabled will
+ * reject such URBs).
+ */
+static int supports_flag_bulk_continuation = -1;
+
+/* Linux 2.6.31 fixes support for the zero length packet URB flag. This
+ * allows us to mark URBs that should be followed by a zero length data
+ * packet, which can be required by device- or class-specific protocols.
+ */
+static int supports_flag_zero_packet = -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 = 0;
+
+/* do we have a descriptors file? */
+static int sysfs_has_descriptors = 0;
+
+/* how many times have we initted (and not exited) ? */
+static volatile int init_count = 0;
+
+/* lock for init_count */
+static pthread_mutex_t hotplug_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static int linux_start_event_monitor(void);
+static int linux_stop_event_monitor(void);
+static int linux_scan_devices(struct libusb_context *ctx);
+
+#if !defined(USE_UDEV)
+static int linux_default_scan_devices (struct libusb_context *ctx);
+#endif
+
+struct linux_device_priv {
+	char *sysfs_dir;
+	unsigned char *dev_descriptor;
+	unsigned char *config_descriptor;
+};
+
+struct linux_device_handle_priv {
+	int fd;
+	uint32_t caps;
+};
+
+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;
+	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)
+{
+	if (usbdev_names)
+		snprintf(path, PATH_MAX, "%s/usbdev%d.%d",
+			usbfs_path, dev->bus_number, dev->device_address);
+	else
+		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;
+}
+
+/* check dirent for a /dev/usbdev%d.%d name
+ * optionally return bus/device on success */
+static int _is_usbdev_entry(struct dirent *entry, int *bus_p, int *dev_p)
+{
+	int busnum, devnum;
+
+	if (sscanf(entry->d_name, "usbdev%d.%d", &busnum, &devnum) != 2)
+		return 0;
+
+	usbi_dbg("found: %s", entry->d_name);
+	if (bus_p != NULL)
+		*bus_p = busnum;
+	if (dev_p != NULL)
+		*dev_p = devnum;
+	return 1;
+}
+
+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;
+	}
+
+	/* look for /dev/usbdev*.* if the normal places fail */
+	if (ret == NULL) {
+		struct dirent *entry;
+		DIR *dir;
+
+		path = "/dev";
+		dir = opendir(path);
+		if (dir != NULL) {
+			while ((entry = readdir(dir)) != NULL) {
+				if (_is_usbdev_entry(entry, NULL, NULL)) {
+					/* found one; that's enough */
+					ret = path;
+					usbdev_names = 1;
+					break;
+				}
+			}
+			closedir(dir);
+		}
+	}
+
+	if (ret != NULL)
+		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)
+{
+#ifdef CLOCK_MONOTONIC
+	struct timespec ts;
+	int r;
+
+	/* 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;
+}
+
+static int kernel_version_ge(int major, int minor, int sublevel)
+{
+	struct utsname uts;
+	int atoms, kmajor, kminor, ksublevel;
+
+	if (uname(&uts) < 0)
+		return -1;
+	atoms = sscanf(uts.release, "%d.%d.%d", &kmajor, &kminor, &ksublevel);
+	if (atoms < 1)
+		return -1;
+
+	if (kmajor > major)
+		return 1;
+	if (kmajor < major)
+		return 0;
+
+	/* kmajor == major */
+	if (atoms < 2)
+		return 0 == minor && 0 == sublevel;
+	if (kminor > minor)
+		return 1;
+	if (kminor < minor)
+		return 0;
+
+	/* kminor == minor */
+	if (atoms < 3)
+		return 0 == sublevel;
+
+	return ksublevel >= sublevel;
+}
+
+/* Return 1 if filename exists inside dirname in sysfs.
+   SYSFS_DEVICE_PATH is assumed to be the beginning of the path. */
+static int sysfs_has_file(const char *dirname, const char *filename)
+{
+	struct stat statbuf;
+	char path[PATH_MAX];
+	int r;
+
+	snprintf(path, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH, dirname, filename);
+	r = stat(path, &statbuf);
+	if (r == 0 && S_ISREG(statbuf.st_mode))
+		return 1;
+
+	return 0;
+}
+
+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) {
+		/* bulk continuation URB flag available from Linux 2.6.32 */
+		supports_flag_bulk_continuation = kernel_version_ge(2,6,32);
+		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");
+
+	if (-1 == supports_flag_zero_packet) {
+		/* zero length packet URB flag fixed since Linux 2.6.31 */
+		supports_flag_zero_packet = kernel_version_ge(2,6,31);
+		if (-1 == supports_flag_zero_packet) {
+			usbi_err(ctx, "error checking for zero length packet support");
+			return LIBUSB_ERROR_OTHER;
+		}
+	}
+
+	if (supports_flag_zero_packet)
+		usbi_dbg("zero length packet flag supported");
+
+	r = stat(SYSFS_DEVICE_PATH, &statbuf);
+	if (r == 0 && S_ISDIR(statbuf.st_mode)) {
+		DIR *devices = opendir(SYSFS_DEVICE_PATH);
+		struct dirent *entry;
+
+		usbi_dbg("found usb devices in sysfs");
+
+		if (!devices) {
+			usbi_err(ctx, "opendir devices failed errno=%d", errno);
+			return LIBUSB_ERROR_IO;
+		}
+
+		/* Make sure sysfs supports all the required files. If it
+		 * does not, then usbfs will be used instead.  Determine
+		 * this by looping through the directories in
+		 * SYSFS_DEVICE_PATH.  With the assumption that there will
+		 * always be subdirectories of the name usbN (usb1, usb2,
+		 * etc) representing the root hubs, check the usbN
+		 * subdirectories to see if they have all the needed files.
+		 * This algorithm uses the usbN subdirectories (root hubs)
+		 * because a device disconnection will cause a race
+		 * condition regarding which files are available, sometimes
+		 * causing an incorrect result.  The root hubs are used
+		 * because it is assumed that they will always be present.
+		 * See the "sysfs vs usbfs" comment at the top of this file
+		 * for more details.  */
+		while ((entry = readdir(devices))) {
+			int has_busnum=0, has_devnum=0, has_descriptors=0;
+			int has_configuration_value=0;
+
+			/* Only check the usbN directories. */
+			if (strncmp(entry->d_name, "usb", 3) != 0)
+				continue;
+
+			/* Check for the files libusb needs from sysfs. */
+			has_busnum = sysfs_has_file(entry->d_name, "busnum");
+			has_devnum = sysfs_has_file(entry->d_name, "devnum");
+			has_descriptors = sysfs_has_file(entry->d_name, "descriptors");
+			has_configuration_value = sysfs_has_file(entry->d_name, "bConfigurationValue");
+
+			if (has_busnum && has_devnum && has_configuration_value)
+				sysfs_can_relate_devices = 1;
+			if (has_descriptors)
+				sysfs_has_descriptors = 1;
+
+			/* Only need to check until we've found ONE device which
+			   has all the attributes. */
+			if (sysfs_has_descriptors && sysfs_can_relate_devices)
+				break;
+		}
+		closedir(devices);
+
+		/* Only use sysfs descriptors if the rest of
+		   sysfs will work for libusb. */
+		if (!sysfs_can_relate_devices)
+			sysfs_has_descriptors = 0;
+	} else {
+		usbi_dbg("sysfs usb info not available");
+		sysfs_has_descriptors = 0;
+		sysfs_can_relate_devices = 0;
+	}
+
+        pthread_mutex_lock(&hotplug_lock);
+        if (!init_count++) {
+                /* start up hotplug event handler */
+                r = linux_start_event_monitor();
+                if (LIBUSB_SUCCESS != r) {
+                        usbi_err(ctx, "error starting hotplug event monitor");
+                        return r;
+                }
+        }
+        pthread_mutex_unlock(&hotplug_lock);
+
+        r = linux_scan_devices(ctx);
+        if (LIBUSB_SUCCESS != r) {
+                return r;
+        }
+
+	return r;
+}
+
+static void op_exit(void)
+{
+        if (!init_count) {
+                /* should not happen */
+		return;
+        }
+
+        pthread_mutex_lock(&hotplug_lock);
+        if (!--init_count) {
+                /* tear down event handler */
+                (void)linux_stop_event_monitor();
+        }
+        pthread_mutex_unlock(&hotplug_lock);
+}
+
+static int linux_start_event_monitor(void)
+{
+#if defined(USE_UDEV)
+        return linux_udev_start_event_monitor();
+#else
+        return linux_netlink_start_event_monitor();
+#endif
+}
+
+static int linux_stop_event_monitor(void)
+{
+#if defined(USE_UDEV)
+        return linux_udev_stop_event_monitor();
+#else
+        return linux_netlink_stop_event_monitor();
+#endif
+}
+
+static int linux_scan_devices(struct libusb_context *ctx)
+{
+#if defined(USE_UDEV)
+        return linux_udev_scan_devices(ctx);
+#else
+        return linux_default_scan_devices(ctx);
+#endif
+}
+
+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;
+}
+
+/* Note only suitable for attributes which always read >= 0, < 0 is error */
+static int __read_sysfs_attr(struct libusb_context *ctx,
+	const char *devname, const char *attr)
+{
+	char filename[PATH_MAX];
+	FILE *f;
+	int r, value;
+
+	snprintf(filename, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH,
+		 devname, attr);
+	f = fopen(filename, "r");
+	if (f == NULL) {
+		if (errno == ENOENT) {
+			/* File doesn't exist. Assume the device has been
+			   disconnected (see trac ticket #70). */
+			return LIBUSB_ERROR_NO_DEVICE;
+		}
+		usbi_err(ctx, "open %s failed errno=%d", filename, errno);
+		return LIBUSB_ERROR_IO;
+	}
+
+	r = fscanf(f, "%d", &value);
+	fclose(f);
+	if (r != 1) {
+		usbi_err(ctx, "fscanf %s returned %d, errno=%d", attr, r, errno);
+		return LIBUSB_ERROR_NO_DEVICE; /* For unplug race (trac #70) */
+	}
+	if (value < 0) {
+		usbi_err(ctx, "%s contains a negative value", filename);
+		return LIBUSB_ERROR_IO;
+	}
+
+	return value;
+}
+
+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) {
+		*host_endian = 0;
+		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;
+	ssize_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_dbg("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;
+	ssize_t 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;
+}
+
+int linux_get_device_address (struct libusb_context *ctx, int detached,
+			      uint8_t *busnum, uint8_t *devaddr,
+			      const char *dev_node, const char *sys_name)
+{
+	usbi_dbg("getting address for device: %s detached: %d",
+		 sys_name, detached);
+        /* can't use sysfs to read the bus and device number if the
+           device has been detached */
+        if (!sysfs_can_relate_devices || detached || NULL == sys_name) {
+		if (NULL == dev_node) {
+			return LIBUSB_ERROR_OTHER;
+		}
+
+                /* will this work with all supported kernel versions? */
+                if (!strncmp(dev_node, "/dev/bus/usb", 12)) {
+                        sscanf (dev_node, "/dev/bus/usb/%hhd/%hhd", busnum, devaddr);
+                } else if (!strncmp(dev_node, "/proc/bus/usb", 13)) {
+                        sscanf (dev_node, "/proc/bus/usb/%hhd/%hhd", busnum, devaddr);
+                }
+
+                return LIBUSB_SUCCESS;
+        }
+
+	usbi_dbg("scan %s", sys_name);
+
+        *busnum = __read_sysfs_attr(ctx, sys_name, "busnum");
+        if (0 > *busnum)
+                return *busnum;
+                
+        *devaddr = __read_sysfs_attr(ctx, sys_name, "devnum");
+        if (0 > *devaddr)
+                return *devaddr;
+
+	usbi_dbg("bus=%d dev=%d", *busnum, *devaddr);
+	if (*busnum > 255 || *devaddr > 255)
+		return LIBUSB_ERROR_INVALID_PARAM;
+
+        return LIBUSB_SUCCESS;
+}
+
+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, speed;
+	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);
+
+		/* Note speed can contain 1.5, in this case __read_sysfs_attr
+		   will stop parsing at the '.' and return 1 */
+		speed = __read_sysfs_attr(DEVICE_CTX(dev), sysfs_dir, "speed");
+		if (speed >= 0) {
+			switch (speed) {
+			case     1: dev->speed = LIBUSB_SPEED_LOW; break;
+			case    12: dev->speed = LIBUSB_SPEED_FULL; break;
+			case   480: dev->speed = LIBUSB_SPEED_HIGH; break;
+			case  5000: dev->speed = LIBUSB_SPEED_SUPER; break;
+			default:
+				usbi_warn(DEVICE_CTX(dev), "Unknown device speed: %d Mbps", speed);
+			}
+		}
+	}
+
+	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;
+}
+
+int linux_enumerate_device(struct libusb_context *ctx,
+		     uint8_t busnum, uint8_t devaddr,
+		     const char *sysfs_dir)
+{
+	unsigned long session_id;
+	struct libusb_device *dev;
+	int r = 0;
+
+	/* FIXME: session ID is not guaranteed unique as addresses can wrap and
+	 * will be reused. instead we should add a simple sysfs attribute with
+	 * a session ID. */
+	session_id = busnum << 8 | devaddr;
+	usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr,
+		session_id);
+
+	usbi_dbg("allocating new device for %d/%d (session %ld)",
+		 busnum, devaddr, session_id);
+	dev = usbi_alloc_device(ctx, session_id);
+	if (!dev)
+		return LIBUSB_ERROR_NO_MEM;
+
+	r = initialize_device(dev, busnum, devaddr, sysfs_dir);
+	if (r < 0)
+		goto out;
+	r = usbi_sanitize_device(dev);
+	if (r < 0)
+		goto out;
+out:
+	if (r < 0)
+		libusb_unref_device(dev);
+	else
+		usbi_connect_device(dev);
+
+	return r;
+}
+
+void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name)
+{
+	struct libusb_context *ctx;
+
+	list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+		if (usbi_get_device_by_session_id(ctx, busnum << 8 | devaddr)) {
+			/* device already exists in the context */
+			usbi_dbg("device already exists in context");
+			continue;
+		}
+
+		linux_enumerate_device(ctx, busnum, devaddr, sys_name);
+	}
+}
+
+void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name)
+{
+	struct libusb_context *ctx;
+	struct libusb_device *dev;
+
+	list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+		dev = usbi_get_device_by_session_id (ctx, busnum << 8 | devaddr);
+		if (NULL != dev) {
+			usbi_disconnect_device (dev);
+		} else {
+			usbi_err(ctx, "device not found for session %x", busnum << 8 | devaddr);
+		}
+	}
+}
+
+#if !defined(USE_UDEV)
+/* open a bus directory and adds all discovered devices to the context */
+static int usbfs_scan_busdir(struct libusb_context *ctx, uint8_t busnum)
+{
+	DIR *dir;
+	char dirpath[PATH_MAX];
+	struct dirent *entry;
+	int r = LIBUSB_ERROR_IO;
+
+	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 r;
+	}
+
+	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;
+		}
+
+		if (linux_enumerate_device(ctx, busnum, (uint8_t) devaddr, NULL)) {
+			usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
+			continue;
+		}
+
+		r = 0;
+	}
+
+	closedir(dir);
+	return r;
+}
+
+static int usbfs_get_device_list(struct libusb_context *ctx)
+{
+	struct dirent *entry;
+	DIR *buses = opendir(usbfs_path);
+	int r = 0;
+
+	if (!buses) {
+		usbi_err(ctx, "opendir buses failed errno=%d", errno);
+		return LIBUSB_ERROR_IO;
+	}
+
+	while ((entry = readdir(buses))) {
+		int busnum;
+
+		if (entry->d_name[0] == '.')
+			continue;
+
+		if (usbdev_names) {
+			int devaddr;
+			if (!_is_usbdev_entry(entry, &busnum, &devaddr))
+				continue;
+
+			r = linux_enumerate_device(ctx, busnum, (uint8_t) devaddr, NULL);
+			if (r < 0) {
+				usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
+				continue;
+			}
+		} else {
+			busnum = atoi(entry->d_name);
+			if (busnum == 0) {
+				usbi_dbg("unknown dir entry %s", entry->d_name);
+				continue;
+			}
+
+			r = usbfs_scan_busdir(ctx, busnum);
+			if (r < 0)
+				break;
+		}
+	}
+
+	closedir(buses);
+	return r;
+
+}
+
+static int sysfs_scan_device(struct libusb_context *ctx, const char *devname)
+{
+	uint8_t busnum, devaddr;
+	int ret;
+
+	ret = linux_get_device_address (ctx, 0, &busnum, &devaddr, NULL, devname);
+	if (LIBUSB_SUCCESS != ret) {
+		return ret;
+	}
+
+	return linux_enumerate_device(ctx, busnum & 0xff, devaddr & 0xff,
+		devname);
+}
+
+static int sysfs_get_device_list(struct libusb_context *ctx)
+{
+	DIR *devices = opendir(SYSFS_DEVICE_PATH);
+	struct dirent *entry;
+	int r = LIBUSB_ERROR_IO;
+
+	if (!devices) {
+		usbi_err(ctx, "opendir devices failed errno=%d", errno);
+		return r;
+	}
+
+	while ((entry = readdir(devices))) {
+		if ((!isdigit(entry->d_name[0]) && strncmp(entry->d_name, "usb", 3))
+				|| strchr(entry->d_name, ':'))
+			continue;
+
+		if (sysfs_scan_device(ctx, entry->d_name)) {
+			usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
+			continue;
+		}
+
+		r = 0;
+	}
+
+	closedir(devices);
+	return r;
+}
+
+static int linux_default_scan_devices (struct libusb_context *ctx)
+{
+	/* 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 at the top of this
+	 * file, sometimes we have sysfs but not enough information to
+	 * relate sysfs devices to usbfs nodes.  op_init() determines the
+	 * adequacy of sysfs and sets sysfs_can_relate_devices.
+	 */
+	if (sysfs_can_relate_devices != 0)
+		return sysfs_get_device_list(ctx);
+	else
+		return usbfs_get_device_list(ctx);
+}
+#endif
+
+static int op_open(struct libusb_device_handle *handle)
+{
+	struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
+	char filename[PATH_MAX];
+	int r;
+
+	_get_usbfs_path(handle->dev, filename);
+	usbi_dbg("opening %s", 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) {
+			usbi_err(HANDLE_CTX(handle), "libusb couldn't open USB device %s: "
+				"No such file or directory.", filename);
+			return LIBUSB_ERROR_NO_DEVICE;
+		} else {
+			usbi_err(HANDLE_CTX(handle),
+				"open failed, code %d errno %d", hpriv->fd, errno);
+			return LIBUSB_ERROR_IO;
+		}
+	}
+
+	r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps);
+	if (r < 0) {
+		if (errno == ENOTTY)
+			usbi_dbg("%s: getcap not available", filename);
+		else
+			usbi_err(HANDLE_CTX(handle),
+				 "%s: getcap failed (%d)", filename, errno);
+		hpriv->caps = 0;
+		if (supports_flag_zero_packet)
+			hpriv->caps |= USBFS_CAP_ZERO_PACKET;
+		if (supports_flag_bulk_continuation)
+			hpriv->caps |= USBFS_CAP_BULK_CONTINUATION;
+	}
+
+	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 (r < 0)
+		return r;
+
+	if (*config == -1) {
+		usbi_err(HANDLE_CTX(handle), "device unconfigured");
+		*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 i, r, ret = 0;
+
+	/* Doing a device reset will cause the usbfs driver to get unbound
+	   from any interfaces it is bound to. By voluntarily unbinding
+	   the usbfs driver ourself, we stop the kernel from rebinding
+	   the interface after reset (which would end up with the interface
+	   getting bound to the in kernel driver if any). */
+	for (i = 0; i < USB_MAXINTERFACES; i++) {
+		if (handle->claimed_interfaces & (1L << i)) {
+			op_release_interface(handle, i);
+		}
+	}
+
+	usbi_mutex_lock(&handle->lock);
+	r = ioctl(fd, IOCTL_USBFS_RESET, NULL);
+	if (r) {
+		if (errno == ENODEV) {
+			ret = LIBUSB_ERROR_NOT_FOUND;
+			goto out;
+		}
+
+		usbi_err(HANDLE_CTX(handle),
+			"reset failed error %d errno %d", r, errno);
+		ret = LIBUSB_ERROR_OTHER;
+		goto out;
+	}
+
+	/* And re-claim any interfaces which were claimed before the reset */
+	for (i = 0; i < USB_MAXINTERFACES; i++) {
+		if (handle->claimed_interfaces & (1L << i)) {
+			r = op_claim_interface(handle, i);
+			if (r) {
+				usbi_warn(HANDLE_CTX(handle),
+					"failed to re-claim interface %d after reset", i);
+				handle->claimed_interfaces &= ~(1L << i);
+			}
+		}
+	}
+out:
+	usbi_mutex_unlock(&handle->lock);
+	return ret;
+}
+
+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);
+}
+
+/* URBs are discarded in reverse order of submission to avoid races. */
+static int discard_urbs(struct usbi_transfer *itransfer, int first, int last_plus_one)
+{
+	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);
+	int i, ret = 0;
+	struct usbfs_urb *urb;
+
+	for (i = last_plus_one - 1; i >= first; i--) {
+		if (LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type)
+			urb = tpriv->iso_urbs[i];
+		else
+			urb = &tpriv->urbs[i];
+
+		if (0 == ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, urb))
+			continue;
+
+		if (EINVAL == errno) {
+			usbi_dbg("URB not found --> assuming ready to be reaped");
+			if (i == (last_plus_one - 1))
+				ret = LIBUSB_ERROR_NOT_FOUND;
+		} else if (ENODEV == errno) {
+			usbi_dbg("Device not found for URB --> assuming ready to be reaped");
+			ret = LIBUSB_ERROR_NO_DEVICE;
+		} else {
+			usbi_warn(TRANSFER_CTX(transfer),
+				"unrecognised discard errno %d", errno);
+			ret = LIBUSB_ERROR_OTHER;
+		}
+	}
+	return ret;
+}
+
+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 bulk_buffer_len, use_bulk_continuation;
+	int r;
+	int i;
+	size_t alloc_size;
+
+	if (tpriv->urbs)
+		return LIBUSB_ERROR_BUSY;
+
+	if (is_out && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) &&
+			!(dpriv->caps & USBFS_CAP_ZERO_PACKET))
+		return LIBUSB_ERROR_NOT_SUPPORTED;
+
+	/*
+	 * Older versions of usbfs place a 16kb limit on bulk URBs. We work
+	 * around this by splitting large transfers into 16k blocks, and then
+	 * submit all urbs at once. it would be simpler to submit one urb at
+	 * a time, but there is a big performance gain doing it this way.
+	 *
+	 * Newer versions lift the 16k limit (USBFS_CAP_NO_PACKET_SIZE_LIM),
+	 * using arbritary large transfers can still be a bad idea though, as
+	 * the kernel needs to allocate physical contiguous memory for this,
+	 * which may fail for large buffers.
+	 *
+	 * The kernel solves this problem by splitting the transfer into
+	 * blocks itself when the host-controller is scatter-gather capable
+	 * (USBFS_CAP_BULK_SCATTER_GATHER), which most controllers are.
+	 *
+	 * Last, there is the issue of short-transfers when splitting, for
+	 * short split-transfers to work reliable USBFS_CAP_BULK_CONTINUATION
+	 * is needed, but this is not always available.
+	 */
+	if (dpriv->caps & USBFS_CAP_BULK_SCATTER_GATHER) {
+		/* Good! Just submit everything in one go */
+		bulk_buffer_len = transfer->length ? transfer->length : 1;
+		use_bulk_continuation = 0;
+	} else if (dpriv->caps & USBFS_CAP_BULK_CONTINUATION) {
+		/* Split the transfers and use bulk-continuation to
+		   avoid issues with short-transfers */
+		bulk_buffer_len = MAX_BULK_BUFFER_LENGTH;
+		use_bulk_continuation = 1;
+	} else if (dpriv->caps & USBFS_CAP_NO_PACKET_SIZE_LIM) {
+		/* Don't split, assume the kernel can alloc the buffer
+		   (otherwise the submit will fail with -ENOMEM) */
+		bulk_buffer_len = transfer->length ? transfer->length : 1;
+		use_bulk_continuation = 0;
+	} else {
+		/* Bad, splitting without bulk-continuation, short transfers
+		   which end before the last urb will not work reliable! */
+		/* Note we don't warn here as this is "normal" on kernels <
+		   2.6.32 and not a problem for most applications */
+		bulk_buffer_len = MAX_BULK_BUFFER_LENGTH;
+		use_bulk_continuation = 0;
+	}
+
+	int num_urbs = transfer->length / bulk_buffer_len;
+	int last_urb_partial = 0;
+
+	if (transfer->length == 0) {
+		num_urbs = 1;
+	} else if ((transfer->length % bulk_buffer_len) > 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 * bulk_buffer_len);
+                /* don't set the short not ok flag for the last URB */
+		if (use_bulk_continuation && !is_out && i < num_urbs - 1)
+			urb->flags = USBFS_URB_SHORT_NOT_OK;
+		if (i == num_urbs - 1 && last_urb_partial)
+			urb->buffer_length = transfer->length % bulk_buffer_len;
+		else if (transfer->length == 0)
+			urb->buffer_length = 0;
+		else
+			urb->buffer_length = bulk_buffer_len;
+
+		if (i > 0 && use_bulk_continuation)
+			urb->flags |= USBFS_URB_BULK_CONTINUATION;
+
+		/* we have already checked that the flag is supported */
+		if (is_out && i == num_urbs - 1 &&
+		    transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)
+			urb->flags |= USBFS_URB_ZERO_PACKET;
+
+		r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb);
+		if (r < 0) {
+			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;
+
+			discard_urbs(itransfer, 0, i);
+
+			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.
+	 *
+	 * Newer kernels lift the 32k limit (USBFS_CAP_NO_PACKET_SIZE_LIM),
+	 * using arbritary large transfers is still be a bad idea though, as
+	 * the kernel needs to allocate physical contiguous memory for this,
+	 * which may fail for large buffers.
+	 */
+
+	/* calculate how many URBs we need */
+	for (i = 0; i < num_packets; i++) {
+		unsigned 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;
+		unsigned 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) {
+			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;
+			discard_urbs(itransfer, 0, i);
+
+			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->num_urbs = 1;
+	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 op_cancel_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);
+
+	switch (transfer->type) {
+	case LIBUSB_TRANSFER_TYPE_BULK:
+		if (tpriv->reap_action == ERROR)
+			break;
+		/* else, fall through */
+	case LIBUSB_TRANSFER_TYPE_CONTROL:
+	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+		tpriv->reap_action = CANCELLED;
+		break;
+	default:
+		usbi_err(TRANSFER_CTX(transfer),
+			"unknown endpoint type %d", transfer->type);
+		return LIBUSB_ERROR_INVALID_PARAM;
+	}
+
+	if (!tpriv->urbs)
+		return LIBUSB_ERROR_NOT_FOUND;
+
+	return discard_urbs(itransfer, 0, tpriv->num_urbs);
+}
+
+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);
+
+	/* urbs can be freed also in submit_transfer so lock mutex first */
+	switch (transfer->type) {
+	case LIBUSB_TRANSFER_TYPE_CONTROL:
+	case LIBUSB_TRANSFER_TYPE_BULK:
+	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+		usbi_mutex_lock(&itransfer->lock);
+		if (tpriv->urbs)
+			free(tpriv->urbs);
+		tpriv->urbs = NULL;
+		usbi_mutex_unlock(&itransfer->lock);
+		break;
+	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+		usbi_mutex_lock(&itransfer->lock);
+		if (tpriv->iso_urbs)
+			free_iso_urbs(tpriv);
+		usbi_mutex_unlock(&itransfer->lock);
+		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);
+	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).
+		 *    (this can't happen since we always use BULK_CONTINUATION.)
+		 *
+		 * 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;
+	}
+
+	itransfer->transferred += urb->actual_length;
+
+	/* Many of these errors can occur on *any* urb of a multi-urb
+	 * transfer.  When they do, we tear down the rest of the transfer.
+	 */
+	switch (urb->status) {
+	case 0:
+		break;
+	case -EREMOTEIO: /* short transfer */
+		break;
+	case -ENOENT: /* cancelled */
+	case -ECONNRESET:
+		break;
+	case -ENODEV:
+	case -ESHUTDOWN:
+		usbi_dbg("device removed");
+		tpriv->reap_status = LIBUSB_TRANSFER_NO_DEVICE;
+		goto cancel_remaining;
+	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:
+	case -ECOMM:
+	case -ENOSR:
+		usbi_dbg("low level error %d", urb->status);
+		tpriv->reap_action = ERROR;
+		goto cancel_remaining;
+	default:
+		usbi_warn(ITRANSFER_CTX(itransfer),
+			"unrecognised urb status %d", urb->status);
+		tpriv->reap_action = 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 (ERROR == tpriv->reap_action && LIBUSB_TRANSFER_COMPLETED == tpriv->reap_status)
+		tpriv->reap_status = LIBUSB_TRANSFER_ERROR;
+
+	if (tpriv->num_retired == tpriv->num_urbs) /* nothing to cancel */
+		goto completed;
+
+	/* cancel remaining urbs and wait for their completion before
+	 * reporting results */
+	discard_urbs(itransfer, urb_idx + 1, tpriv->num_urbs);
+
+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;
+	enum libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED;
+
+	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);
+
+	/* 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 = LIBUSB_TRANSFER_COMPLETED;
+		switch (urb_desc->status) {
+		case 0:
+			break;
+		case -ENOENT: /* cancelled */
+		case -ECONNRESET:
+			break;
+		case -ENODEV:
+		case -ESHUTDOWN:
+			usbi_dbg("device removed");
+			lib_desc->status = LIBUSB_TRANSFER_NO_DEVICE;
+			break;
+		case -EPIPE:
+			usbi_dbg("detected endpoint stall");
+			lib_desc->status = LIBUSB_TRANSFER_STALL;
+			break;
+		case -EOVERFLOW:
+			usbi_dbg("overflow error");
+			lib_desc->status = LIBUSB_TRANSFER_OVERFLOW;
+			break;
+		case -ETIME:
+		case -EPROTO:
+		case -EILSEQ:
+		case -ECOMM:
+		case -ENOSR:
+		case -EXDEV:
+			usbi_dbg("low-level USB error %d", urb_desc->status);
+			lib_desc->status = LIBUSB_TRANSFER_ERROR;
+			break;
+		default:
+			usbi_warn(TRANSFER_CTX(transfer),
+				"unrecognised urb status %d", urb_desc->status);
+			lib_desc->status = LIBUSB_TRANSFER_ERROR;
+			break;
+		}
+		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 -ENOENT: /* cancelled */
+	case -ECONNRESET:
+		break;
+	case -ESHUTDOWN:
+		usbi_dbg("device removed");
+		status = LIBUSB_TRANSFER_NO_DEVICE;
+		break;
+	default:
+		usbi_warn(TRANSFER_CTX(transfer),
+			"unrecognised urb status %d", urb->status);
+		status = LIBUSB_TRANSFER_ERROR;
+		break;
+	}
+
+	/* if we're the last urb 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, status);
+	}
+
+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);
+
+	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:
+		status = LIBUSB_TRANSFER_COMPLETED;
+		break;
+	case -ENOENT: /* cancelled */
+		status = LIBUSB_TRANSFER_CANCELLED;
+		break;
+	case -ENODEV:
+	case -ESHUTDOWN:
+		usbi_dbg("device removed");
+		status = LIBUSB_TRANSFER_NO_DEVICE;
+		break;
+	case -EPIPE:
+		usbi_dbg("unsupported control request");
+		status = LIBUSB_TRANSFER_STALL;
+		break;
+	case -EOVERFLOW:
+		usbi_dbg("control overflow error");
+		status = LIBUSB_TRANSFER_OVERFLOW;
+		break;
+	case -ETIME:
+	case -EPROTO:
+	case -EILSEQ:
+	case -ECOMM:
+	case -ENOSR:
+		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, POLL_NFDS_TYPE nfds, int num_ready)
+{
+	int r;
+	unsigned 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;
+		}
+
+		do {
+			r = reap_for_handle(handle);
+		} while (r == 0);
+		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 = op_exit,
+	.get_device_list = NULL,
+	.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,
+};
+

+ 168 - 0
compat/libusb-1.0/libusb/os/linux_usbfs.h

@@ -0,0 +1,168 @@
+/*
+ * 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
+
+#include <linux/types.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
+#define USBFS_URB_ZERO_PACKET		0x40
+
+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 USBFS_CAP_ZERO_PACKET		0x01
+#define USBFS_CAP_BULK_CONTINUATION	0x02
+#define USBFS_CAP_NO_PACKET_SIZE_LIM	0x04
+#define USBFS_CAP_BULK_SCATTER_GATHER	0x08
+
+#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)
+#define IOCTL_USBFS_CLAIM_PORT	_IOR('U', 24, unsigned int)
+#define IOCTL_USBFS_RELEASE_PORT	_IOR('U', 25, unsigned int)
+#define IOCTL_USBFS_GET_CAPABILITIES	_IOR('U', 26, __u32)
+
+#if defined(HAVE_LIBUDEV)
+int linux_udev_start_event_monitor(void);
+int linux_udev_stop_event_monitor(void);
+int linux_udev_scan_devices(struct libusb_context *ctx);
+#else
+int linux_netlink_start_event_monitor(void);
+int linux_netlink_stop_event_monitor(void);
+#endif
+
+void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name);
+void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name);
+
+int linux_get_device_address (struct libusb_context *ctx, int detached,
+			      uint8_t *busnum, uint8_t *devaddr,
+			      const char *dev_node, const char *sys_name);
+int linux_enumerate_device(struct libusb_context *ctx,
+			   uint8_t busnum, uint8_t devaddr,
+			   const char *sysfs_dir);
+
+#endif

+ 727 - 0
compat/libusb-1.0/libusb/os/openbsd_usb.c

@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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 <sys/time.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <dev/usb/usb.h>
+
+#include "libusb.h"
+#include "libusbi.h"
+
+struct device_priv {
+	char devnode[16];
+	int fd;
+
+	unsigned char *cdesc;			/* active config descriptor */
+	usb_device_descriptor_t ddesc;		/* usb device descriptor */
+};
+
+struct handle_priv {
+	int pipe[2];				/* for event notification */
+	int endpoints[USB_MAX_ENDPOINTS];
+};
+
+/*
+ * Backend functions
+ */
+static int obsd_get_device_list(struct libusb_context *,
+    struct discovered_devs **);
+static int obsd_open(struct libusb_device_handle *);
+static void obsd_close(struct libusb_device_handle *);
+
+static int obsd_get_device_descriptor(struct libusb_device *, unsigned char *,
+    int *);
+static int obsd_get_active_config_descriptor(struct libusb_device *,
+    unsigned char *, size_t, int *);
+static int obsd_get_config_descriptor(struct libusb_device *, uint8_t,
+    unsigned char *, size_t, int *);
+
+static int obsd_get_configuration(struct libusb_device_handle *, int *);
+static int obsd_set_configuration(struct libusb_device_handle *, int);
+
+static int obsd_claim_interface(struct libusb_device_handle *, int);
+static int obsd_release_interface(struct libusb_device_handle *, int);
+
+static int obsd_set_interface_altsetting(struct libusb_device_handle *, int,
+    int);
+static int obsd_clear_halt(struct libusb_device_handle *, unsigned char);
+static int obsd_reset_device(struct libusb_device_handle *);
+static void obsd_destroy_device(struct libusb_device *);
+
+static int obsd_submit_transfer(struct usbi_transfer *);
+static int obsd_cancel_transfer(struct usbi_transfer *);
+static void obsd_clear_transfer_priv(struct usbi_transfer *);
+static int obsd_handle_events(struct libusb_context *ctx, struct pollfd *,
+    nfds_t, int);
+static int obsd_clock_gettime(int, struct timespec *);
+
+/*
+ * Private functions
+ */
+static int _errno_to_libusb(int);
+static int _cache_active_config_descriptor(struct libusb_device *, int);
+static int _sync_control_transfer(struct usbi_transfer *);
+static int _sync_gen_transfer(struct usbi_transfer *);
+static int _access_endpoint(struct libusb_transfer *);
+
+const struct usbi_os_backend openbsd_backend = {
+	"Synchronous OpenBSD backend",
+	NULL,				/* init() */
+	NULL,				/* exit() */
+	obsd_get_device_list,
+	obsd_open,
+	obsd_close,
+
+	obsd_get_device_descriptor,
+	obsd_get_active_config_descriptor,
+	obsd_get_config_descriptor,
+
+	obsd_get_configuration,
+	obsd_set_configuration,
+
+	obsd_claim_interface,
+	obsd_release_interface,
+
+	obsd_set_interface_altsetting,
+	obsd_clear_halt,
+	obsd_reset_device,
+
+	NULL,				/* kernel_driver_active() */
+	NULL,				/* detach_kernel_driver() */
+	NULL,				/* attach_kernel_driver() */
+
+	obsd_destroy_device,
+
+	obsd_submit_transfer,
+	obsd_cancel_transfer,
+	obsd_clear_transfer_priv,
+
+	obsd_handle_events,
+
+	obsd_clock_gettime,
+	sizeof(struct device_priv),
+	sizeof(struct handle_priv),
+	0,				/* transfer_priv_size */
+	0,				/* add_iso_packet_size */
+};
+
+int
+obsd_get_device_list(struct libusb_context * ctx,
+	struct discovered_devs **discdevs)
+{
+	struct libusb_device *dev;
+	struct device_priv *dpriv;
+	struct usb_device_info di;
+	unsigned long session_id;
+	char devnode[16];
+	int fd, err, i;
+
+	usbi_dbg("");
+
+	/* Only ugen(4) is supported */
+	for (i = 0; i < USB_MAX_DEVICES; i++) {
+		/* Control endpoint is always .00 */
+		snprintf(devnode, sizeof(devnode), "/dev/ugen%d.00", i);
+
+		if ((fd = open(devnode, O_RDONLY)) < 0) {
+			if (errno != ENOENT && errno != ENXIO)
+				usbi_err(ctx, "could not open %s", devnode);
+			continue;
+		}
+
+		if (ioctl(fd, USB_GET_DEVICEINFO, &di) < 0)
+			continue;
+
+		session_id = (di.udi_bus << 8 | di.udi_addr);
+		dev = usbi_get_device_by_session_id(ctx, session_id);
+
+		if (dev == NULL) {
+			dev = usbi_alloc_device(ctx, session_id);
+			if (dev == NULL)
+				return (LIBUSB_ERROR_NO_MEM);
+
+			dev->bus_number = di.udi_bus;
+			dev->device_address = di.udi_addr;
+			dev->speed = di.udi_speed;
+
+			dpriv = (struct device_priv *)dev->os_priv;
+			strlcpy(dpriv->devnode, devnode, sizeof(devnode));
+			dpriv->fd = -1;
+
+			if (ioctl(fd, USB_GET_DEVICE_DESC, &dpriv->ddesc) < 0) {
+				err = errno;
+				goto error;
+			}
+
+			dpriv->cdesc = NULL;
+			if (_cache_active_config_descriptor(dev, fd)) {
+				err = errno;
+				goto error;
+			}
+
+			if ((err = usbi_sanitize_device(dev)))
+				goto error;
+		}
+		close(fd);
+
+		if (discovered_devs_append(*discdevs, dev) == NULL)
+			return (LIBUSB_ERROR_NO_MEM);
+	}
+
+	return (LIBUSB_SUCCESS);
+
+error:
+	close(fd);
+	libusb_unref_device(dev);
+	return _errno_to_libusb(err);
+}
+
+int
+obsd_open(struct libusb_device_handle *handle)
+{
+	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
+	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
+
+	dpriv->fd = open(dpriv->devnode, O_RDWR);
+	if (dpriv->fd < 0) {
+		dpriv->fd = open(dpriv->devnode, O_RDONLY);
+		if (dpriv->fd < 0)
+			return _errno_to_libusb(errno);
+	}
+
+	usbi_dbg("open %s: fd %d", dpriv->devnode, dpriv->fd);
+
+	if (pipe(hpriv->pipe) < 0)
+		return _errno_to_libusb(errno);
+
+	return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->pipe[0], POLLIN);
+}
+
+void
+obsd_close(struct libusb_device_handle *handle)
+{
+	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
+	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
+
+	usbi_dbg("close: fd %d", dpriv->fd);
+
+	close(dpriv->fd);
+	dpriv->fd = -1;
+
+	usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]);
+
+	close(hpriv->pipe[0]);
+	close(hpriv->pipe[1]);
+}
+
+int
+obsd_get_device_descriptor(struct libusb_device *dev, unsigned char *buf,
+    int *host_endian)
+{
+	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
+
+	usbi_dbg("");
+
+	memcpy(buf, &dpriv->ddesc, DEVICE_DESC_LENGTH);
+
+	*host_endian = 0;
+
+	return (LIBUSB_SUCCESS);
+}
+
+int
+obsd_get_active_config_descriptor(struct libusb_device *dev,
+    unsigned char *buf, size_t len, int *host_endian)
+{
+	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
+	usb_config_descriptor_t *ucd;
+
+	ucd = (usb_config_descriptor_t *) dpriv->cdesc;
+	len = MIN(len, UGETW(ucd->wTotalLength));
+
+	usbi_dbg("len %d", len);
+
+	memcpy(buf, dpriv->cdesc, len);
+
+	*host_endian = 0;
+
+	return (LIBUSB_SUCCESS);
+}
+
+int
+obsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
+    unsigned char *buf, size_t len, int *host_endian)
+{
+	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
+	struct usb_full_desc ufd;
+	int fd, err;
+
+	usbi_dbg("index %d, len %d", idx, len);
+
+	/* A config descriptor may be requested before opening the device */
+	if (dpriv->fd >= 0) {
+		fd = dpriv->fd;
+	} else {
+		fd = open(dpriv->devnode, O_RDONLY);
+		if (fd < 0)
+			return _errno_to_libusb(errno);
+	}
+
+	ufd.ufd_config_index = idx;
+	ufd.ufd_size = len;
+	ufd.ufd_data = buf;
+
+	if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
+		err = errno;
+		if (dpriv->fd < 0)
+			close(fd);
+		return _errno_to_libusb(err);
+	}
+
+	if (dpriv->fd < 0)
+		close(fd);
+
+	*host_endian = 0;
+
+	return (LIBUSB_SUCCESS);
+}
+
+int
+obsd_get_configuration(struct libusb_device_handle *handle, int *config)
+{
+	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
+
+	usbi_dbg("");
+
+	if (ioctl(dpriv->fd, USB_GET_CONFIG, config) < 0)
+		return _errno_to_libusb(errno);
+
+	usbi_dbg("configuration %d", *config);
+
+	return (LIBUSB_SUCCESS);
+}
+
+int
+obsd_set_configuration(struct libusb_device_handle *handle, int config)
+{
+	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
+
+	usbi_dbg("configuration %d", config);
+
+	if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
+		return _errno_to_libusb(errno);
+
+	return _cache_active_config_descriptor(handle->dev, dpriv->fd);
+}
+
+int
+obsd_claim_interface(struct libusb_device_handle *handle, int iface)
+{
+	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
+	int i;
+
+	for (i = 0; i < USB_MAX_ENDPOINTS; i++)
+		hpriv->endpoints[i] = -1;
+
+	return (LIBUSB_SUCCESS);
+}
+
+int
+obsd_release_interface(struct libusb_device_handle *handle, int iface)
+{
+	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
+	int i;
+
+	for (i = 0; i < USB_MAX_ENDPOINTS; i++)
+		if (hpriv->endpoints[i] >= 0)
+			close(hpriv->endpoints[i]);
+
+	return (LIBUSB_SUCCESS);
+}
+
+int
+obsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
+    int altsetting)
+{
+	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
+	struct usb_alt_interface intf;
+
+	usbi_dbg("iface %d, setting %d", iface, altsetting);
+
+	memset(&intf, 0, sizeof(intf));
+
+	intf.uai_interface_index = iface;
+	intf.uai_alt_no = altsetting;
+
+	if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
+		return _errno_to_libusb(errno);
+
+	return (LIBUSB_SUCCESS);
+}
+
+int
+obsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
+{
+	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
+	struct usb_ctl_request req;
+
+	usbi_dbg("");
+
+	req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
+	req.ucr_request.bRequest = UR_CLEAR_FEATURE;
+	USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
+	USETW(req.ucr_request.wIndex, endpoint);
+	USETW(req.ucr_request.wLength, 0);
+
+	if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0)
+		return _errno_to_libusb(errno);
+
+	return (LIBUSB_SUCCESS);
+}
+
+int
+obsd_reset_device(struct libusb_device_handle *handle)
+{
+	usbi_dbg("");
+
+	return (LIBUSB_ERROR_NOT_SUPPORTED);
+}
+
+void
+obsd_destroy_device(struct libusb_device *dev)
+{
+	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
+
+	usbi_dbg("");
+
+	free(dpriv->cdesc);
+}
+
+int
+obsd_submit_transfer(struct usbi_transfer *itransfer)
+{
+	struct libusb_transfer *transfer;
+	struct handle_priv *hpriv;
+	int err = 0;
+
+	usbi_dbg("");
+
+	transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+	hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
+
+	switch (transfer->type) {
+	case LIBUSB_TRANSFER_TYPE_CONTROL:
+		err = _sync_control_transfer(itransfer);
+		break;
+	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+		if (IS_XFEROUT(transfer)) {
+			/* Isochronous write is not supported */
+			err = LIBUSB_ERROR_NOT_SUPPORTED;
+			break;
+		}
+		err = _sync_gen_transfer(itransfer);
+		break;
+	case LIBUSB_TRANSFER_TYPE_BULK:
+	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+		if (IS_XFEROUT(transfer) &&
+		    transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
+			err = LIBUSB_ERROR_NOT_SUPPORTED;
+			break;
+		}
+		err = _sync_gen_transfer(itransfer);
+		break;
+	}
+
+	if (err)
+		return (err);
+
+	if (write(hpriv->pipe[1], &itransfer, sizeof(itransfer)) < 0)
+		return _errno_to_libusb(errno);
+
+	return (LIBUSB_SUCCESS);
+}
+
+int
+obsd_cancel_transfer(struct usbi_transfer *itransfer)
+{
+	usbi_dbg("");
+
+	return (LIBUSB_ERROR_NOT_SUPPORTED);
+}
+
+void
+obsd_clear_transfer_priv(struct usbi_transfer *itransfer)
+{
+	usbi_dbg("");
+
+	/* Nothing to do */
+}
+
+int
+obsd_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds_t nfds,
+    int num_ready)
+{
+	struct libusb_device_handle *handle;
+	struct handle_priv *hpriv = NULL;
+	struct usbi_transfer *itransfer;
+	struct pollfd *pollfd;
+	int i, err = 0;
+
+	usbi_dbg("");
+
+	pthread_mutex_lock(&ctx->open_devs_lock);
+	for (i = 0; i < nfds && num_ready > 0; i++) {
+		pollfd = &fds[i];
+
+		if (!pollfd->revents)
+			continue;
+
+		hpriv = NULL;
+		num_ready--;
+		list_for_each_entry(handle, &ctx->open_devs, list,
+		    struct libusb_device_handle) {
+			hpriv = (struct handle_priv *)handle->os_priv;
+
+			if (hpriv->pipe[0] == pollfd->fd)
+				break;
+
+			hpriv = NULL;
+		}
+
+		if (NULL == hpriv) {
+			usbi_dbg("fd %d is not an event pipe!", pollfd->fd);
+			err = ENOENT;
+			break;
+		}
+
+		if (pollfd->revents & POLLERR) {
+			usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]);
+			usbi_handle_disconnect(handle);
+			continue;
+		}
+
+		if (read(hpriv->pipe[0], &itransfer, sizeof(itransfer)) < 0) {
+			err = errno;
+			break;
+		}
+
+		if ((err = usbi_handle_transfer_completion(itransfer,
+		    LIBUSB_TRANSFER_COMPLETED)))
+			break;
+	}
+	pthread_mutex_unlock(&ctx->open_devs_lock);
+
+	if (err)
+		return _errno_to_libusb(err);
+
+	return (LIBUSB_SUCCESS);
+}
+
+int
+obsd_clock_gettime(int clkid, struct timespec *tp)
+{
+	usbi_dbg("clock %d", clkid);
+
+	if (clkid == USBI_CLOCK_REALTIME)
+		return clock_gettime(CLOCK_REALTIME, tp);
+
+	if (clkid == USBI_CLOCK_MONOTONIC)
+		return clock_gettime(CLOCK_MONOTONIC, tp);
+
+	return (LIBUSB_ERROR_INVALID_PARAM);
+}
+
+int
+_errno_to_libusb(int err)
+{
+	switch (err) {
+	case EIO:
+		return (LIBUSB_ERROR_IO);
+	case EACCES:
+		return (LIBUSB_ERROR_ACCESS);
+	case ENOENT:
+		return (LIBUSB_ERROR_NO_DEVICE);
+	case ENOMEM:
+		return (LIBUSB_ERROR_NO_MEM);
+	}
+
+	usbi_dbg("error: %s", strerror(err));
+
+	return (LIBUSB_ERROR_OTHER);
+}
+
+int
+_cache_active_config_descriptor(struct libusb_device *dev, int fd)
+{
+	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
+	struct usb_config_desc ucd;
+	struct usb_full_desc ufd;
+	unsigned char* buf;
+	int len;
+
+	usbi_dbg("fd %d", fd);
+
+	ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX;
+
+	if ((ioctl(fd, USB_GET_CONFIG_DESC, &ucd)) < 0)
+		return _errno_to_libusb(errno);
+
+	usbi_dbg("active bLength %d", ucd.ucd_desc.bLength);
+
+	len = UGETW(ucd.ucd_desc.wTotalLength);
+	buf = malloc(len);
+	if (buf == NULL)
+		return (LIBUSB_ERROR_NO_MEM);
+
+	ufd.ufd_config_index = ucd.ucd_config_index;
+	ufd.ufd_size = len;
+	ufd.ufd_data = buf;
+
+	usbi_dbg("index %d, len %d", ufd.ufd_config_index, len);
+
+	if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
+		free(buf);
+		return _errno_to_libusb(errno);
+	}
+
+	if (dpriv->cdesc)
+		free(dpriv->cdesc);
+	dpriv->cdesc = buf;
+
+	return (0);
+}
+
+int
+_sync_control_transfer(struct usbi_transfer *itransfer)
+{
+	struct libusb_transfer *transfer;
+	struct libusb_control_setup *setup;
+	struct device_priv *dpriv;
+	struct usb_ctl_request req;
+
+	transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+	dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
+	setup = (struct libusb_control_setup *)transfer->buffer;
+
+	usbi_dbg("type %d request %d value %d index %d length %d timeout %d",
+	    setup->bmRequestType, setup->bRequest,
+	    libusb_le16_to_cpu(setup->wValue),
+	    libusb_le16_to_cpu(setup->wIndex),
+	    libusb_le16_to_cpu(setup->wLength), transfer->timeout);
+
+	req.ucr_request.bmRequestType = setup->bmRequestType;
+	req.ucr_request.bRequest = setup->bRequest;
+	/* Don't use USETW, libusb already deals with the endianness */
+	(*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
+	(*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
+	(*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
+	req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
+
+	if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
+		req.ucr_flags = USBD_SHORT_XFER_OK;
+
+	if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
+		return _errno_to_libusb(errno);
+
+	if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0)
+		return _errno_to_libusb(errno);
+
+	itransfer->transferred = req.ucr_actlen;
+
+	usbi_dbg("transferred %d", itransfer->transferred);
+
+	return (0);
+}
+
+int
+_access_endpoint(struct libusb_transfer *transfer)
+{
+	struct handle_priv *hpriv;
+	struct device_priv *dpriv;
+	char *s, devnode[16];
+	int fd, endpt;
+	mode_t mode;
+
+	hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
+	dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
+
+	endpt = UE_GET_ADDR(transfer->endpoint);
+	mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
+
+	usbi_dbg("endpoint %d mode %d", endpt, mode);
+
+	if (hpriv->endpoints[endpt] < 0) {
+		/* Pick the right node given the control one */
+		strlcpy(devnode, dpriv->devnode, sizeof(devnode));
+		s = strchr(devnode, '.');
+		snprintf(s, 4, ".%02d", endpt);
+
+		/* We may need to read/write to the same endpoint later. */
+		if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
+			if ((fd = open(devnode, mode)) < 0)
+				return (-1);
+
+		hpriv->endpoints[endpt] = fd;
+	}
+
+	return (hpriv->endpoints[endpt]);
+}
+
+int
+_sync_gen_transfer(struct usbi_transfer *itransfer)
+{
+	struct libusb_transfer *transfer;
+	int fd, nr = 1;
+
+	transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+	/*
+	 * Bulk, Interrupt or Isochronous transfer depends on the
+	 * endpoint and thus the node to open.
+	 */
+	if ((fd = _access_endpoint(transfer)) < 0)
+		return _errno_to_libusb(errno);
+
+	if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
+		return _errno_to_libusb(errno);
+
+	if (IS_XFERIN(transfer)) {
+		if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
+			if ((ioctl(fd, USB_SET_SHORT_XFER, &nr)) < 0)
+				return _errno_to_libusb(errno);
+
+		nr = read(fd, transfer->buffer, transfer->length);
+	} else {
+		nr = write(fd, transfer->buffer, transfer->length);
+	}
+
+	if (nr < 0)
+		return _errno_to_libusb(errno);
+
+	itransfer->transferred = nr;
+
+	return (0);
+}

+ 10 - 0
compat/libusb-1.0/libusb/os/poll_posix.h

@@ -0,0 +1,10 @@
+#ifndef LIBUSB_POLL_POSIX_H
+#define LIBUSB_POLL_POSIX_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 */

+ 745 - 0
compat/libusb-1.0/libusb/os/poll_windows.c

@@ -0,0 +1,745 @@
+/*
+ * 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
+// MSVC++ < 2005 cannot use a variadic argument and non MSVC
+// compilers produce warnings if parenthesis are omitted.
+#if defined(_MSC_VER) && _MSC_VER < 1400
+#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)
+
+// 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;
+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)
+static __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;
+
+	while (InterlockedExchange((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);
+		}
+		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 = (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;
+
+	while (InterlockedExchange((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;
+			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 = (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);
+			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;
+
+	CHECK_INIT_POLLING;
+
+	triggered = 0;
+	handles_to_wait_on = (HANDLE*) calloc(nfds+1, sizeof(HANDLE));	// +1 for fd_update
+	handle_to_index = (int*) calloc(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;
+			nb_handles_to_wait_on++;
+		}
+		LeaveCriticalSection(&_poll_fd[_index].mutex);
+	}
+
+	// If nothing was triggered, wait on all fds that require it
+	if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) {
+		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)) {
+			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);
+	}
+	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;
+}

+ 117 - 0
compat/libusb-1.0/libusb/os/poll_windows.h

@@ -0,0 +1,117 @@
+/*
+ * 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
+
+#include <windows.h>
+
+#if defined(_MSC_VER)
+// disable /W4 MSVC warnings that are benign
+#pragma warning(disable:4127) // conditional expression is constant
+#endif
+
+// 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 */
+};
+
+// 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
+

+ 55 - 0
compat/libusb-1.0/libusb/os/threads_posix.c

@@ -0,0 +1,55 @@
+/*
+ * libusb synchronization using POSIX Threads
+ *
+ * Copyright (C) 2011 Vitali Lovich <vlovich@aliph.com>
+ * Copyright (C) 2011 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
+ */
+
+#ifdef _XOPEN_SOURCE
+# if _XOPEN_SOURCE < 500
+#  undef _XOPEN_SOURCE
+#  define _XOPEN_SOURCE 500
+# endif
+#else
+#define _XOPEN_SOURCE 500
+#endif /* _XOPEN_SOURCE */
+
+#include "threads_posix.h"
+
+int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
+{
+	int err;
+	pthread_mutexattr_t stack_attr;
+	if (!attr) {
+		attr = &stack_attr;
+		err = pthread_mutexattr_init(&stack_attr);
+		if (err != 0)
+			return err;
+	}
+
+	err = pthread_mutexattr_settype(attr, PTHREAD_MUTEX_RECURSIVE);
+	if (err != 0)
+		goto finish;
+
+	err = pthread_mutex_init(mutex, attr);
+
+finish:
+	if (attr == &stack_attr)
+		pthread_mutexattr_destroy(&stack_attr);
+
+	return err;
+}

+ 48 - 0
compat/libusb-1.0/libusb/os/threads_posix.h

@@ -0,0 +1,48 @@
+/*
+ * 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
+
+extern int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
+
+#endif /* LIBUSB_THREADS_POSIX_H */

+ 208 - 0
compat/libusb-1.0/libusb/os/threads_windows.c

@@ -0,0 +1,208 @@
+/*
+ * 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"
+
+
+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));
+	while (InterlockedExchange((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);
+		CloseHandle(pos->event);
+		list_del(&pos->list);
+		prev_pos = pos;
+	}
+	free(prev_pos);
+
+	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      = (struct usbi_cond_perthread*) calloc(1, 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);
+}
+

+ 88 - 0
compat/libusb-1.0/libusb/os/threads_windows.h

@@ -0,0 +1,88 @@
+/*
+ * 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
+
+#include <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
+
+// all Windows mutexes are recursive
+#define usbi_mutex_init_recursive(mutex, attr) usbi_mutex_init((mutex), (attr))
+
+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 */
+

+ 3000 - 0
compat/libusb-1.0/libusb/os/windows_usb.c

@@ -0,0 +1,3000 @@
+/*
+ * 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
+ * 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
+ */
+
+#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 <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);
+// 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);
+// 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);
+
+
+// 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;
+usbi_mutex_t autoclaim_lock;
+// 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)
+
+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(_MSC_VER) && _MSC_VER < 1400)
+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)
+ * usb_class: the generic USB class 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.
+ */
+static bool get_devinfo_data(struct libusb_context *ctx,
+	HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, char* usb_class, unsigned _index)
+{
+	if (_index <= 0) {
+		*dev_info = pSetupDiGetClassDevsA(NULL, usb_class, 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.
+ */
+static 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 = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) calloc(size, 1)) == 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.  */
+static 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.  */
+static 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.  */
+static 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 = (char*) calloc(1, 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
+ * If there's no device at the nth level, return 0
+ */
+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;
+	}
+	// 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 = (uint8_t*) calloc(1, 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
+static 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 = (char*) calloc(1, len+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
+ */
+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;
+
+	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 = (struct windows_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_error_name((enum libusb_error)r));
+			}
+		}
+	}
+	usbi_mutex_unlock(&autoclaim_lock);
+}
+
+/*
+ * 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;
+		}
+
+		// We need a lock for proper auto-release
+		usbi_mutex_init(&autoclaim_lock, NULL);
+
+		// 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);
+	}
+	// At this stage, either we went through full init successfully, or didn't need to
+	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 = (unsigned char**) calloc(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) calloc(1, 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] = (unsigned char*) calloc(1, 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_EX 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;
+
+	// If the device address is already set, we can stop here
+	if (dev->device_address != 0) {
+		return LIBUSB_SUCCESS;
+	}
+	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(conn_info);
+		conn_info.ConnectionIndex = (ULONG)port_number;
+		if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &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;
+		}
+		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;
+		switch (conn_info.Speed) {
+		case 0: dev->speed = LIBUSB_SPEED_LOW; break;
+		case 1: dev->speed = LIBUSB_SPEED_FULL; break;
+		case 2: dev->speed = LIBUSB_SPEED_HIGH; break;
+		case 3: dev->speed = LIBUSB_SPEED_SUPER; break;
+		default:
+			usbi_warn(ctx, "Got unknown device speed %d", conn_info.Speed);
+			break;
+		}
+	} else {
+		dev->device_address = UINT8_MAX;	// Hubs from HCD have a devaddr of 255
+		force_hcd_device_descriptor(dev);
+	}
+
+	usbi_sanitize_device(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
+	// 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);
+	}
+
+	if (priv->usb_interface[interface_number].path != NULL) {
+		usbi_warn(ctx, "interface[%d] already set - ignoring: %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];
+	priv->composite_api_flags |= 1<<api;
+
+	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;
+	HDEVINFO dev_info = { 0 };
+	char* usb_class[2] = {"USB", "NUSB3"};
+	SP_DEVINFO_DATA dev_info_data;
+	SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL;
+#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
+	int r = LIBUSB_SUCCESS;
+	int class_index = 0;
+	unsigned int nb_guids, pass, i, j, ancestor;
+	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;
+	BOOL b = FALSE;
+	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 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;
+	nb_guids = DEV_PASS+1;
+
+	unref_list = (libusb_device**) calloc(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;
+		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);
+			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 {
+				// Workaround for a Nec/Renesas USB 3.0 driver bug where root hubs are
+				// being listed under the "NUSB3" PnP Symbolic Name rather than "USB"
+				while ( (class_index < 2) &&
+					    (!(b = get_devinfo_data(ctx, &dev_info, &dev_info_data, usb_class[class_index], i))) ) {
+						class_index++;
+						i = 0;
+				}
+				if (!b) 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 = (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;
+			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:
+				// Go through the ancestors until we see a face we recognize
+				parent_dev = NULL;
+				for (ancestor = 1; parent_dev == NULL; ancestor++) {
+					session_id = get_ancestor_session_id(dev_info_data.DevInst, ancestor);
+					if (session_id == 0) {
+						break;
+					}
+					parent_dev = usbi_get_device_by_session_id(ctx, session_id);
+				}
+				if (parent_dev == NULL) {
+					usbi_dbg("unlisted ancestor for '%s' (newly connected, etc.) - 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] (%d.%d)",
+						session_id, dev->bus_number, dev->device_address);
+				}
+				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 HUB_PASS:
+			case DEV_PASS:
+				// If the device has already been setup, don't do it again
+				if (priv->path != NULL)
+					break;
+				// 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:
+				case USB_API_HUB:
+					break;
+				default:
+					// For other devices, the first interface is the same as the device
+					priv->usb_interface[0].path = (char*) calloc(safe_strlen(priv->path)+1, 1);
+					if (priv->usb_interface[0].path != NULL) {
+						safe_strcpy(priv->usb_interface[0].path, safe_strlen(priv->path)+1, priv->path);
+					} else {
+						usbi_warn(ctx, "could not duplicate interface path '%s'", 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 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:	// later passes
+				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 = DEV_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);
+
+	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 = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
+
+	usbi_free_fd(transfer_priv->pollable_fd.fd);
+	// When auto claim is in use, attempt to release the auto-claimed interface
+	auto_release(itransfer);
+}
+
+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 = (struct windows_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)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
+
+	itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
+	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 = (struct windows_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)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
+
+	itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
+	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 = (struct windows_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);
+
+	itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
+	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:
+		if (IS_XFEROUT(transfer) &&
+		    transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)
+			return LIBUSB_ERROR_NOT_SUPPORTED;
+		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);
+
+	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, (enum libusb_transfer_status)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, POLL_NFDS_TYPE nfds, int num_ready)
+{
+	struct windows_transfer_priv* transfer_priv = NULL;
+	POLL_NFDS_TYPE 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: %I64u 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);
+
+			nb_responses = InterlockedExchange((LONG*)&request_count[0], 0);
+			if ( (nb_responses)
+			  && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0) ) {
+				usbi_dbg("unable to release timer semaphore %d: %s", windows_error_str(0));
+			}
+			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) {
+			while (1) {
+				InterlockedIncrement((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", "USBHUB3", "NUSB3HUB", "FLXHCIH", "TIHUB3", "ETRONHUB3", "VIAHUB3", "ASMTHUB3"};
+const char* composite_driver_names[] = {"USBCCGP"};
+const char* winusb_driver_names[] = {"WINUSB"};
+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,
+		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_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,
+	},
+};
+
+
+/*
+ * 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
+		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 using WinUSB that you
+		// must first claim the first interface before you claim any other
+		if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) {
+			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;
+			}
+		}
+		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 winusb_get_valid_interface(struct libusb_device_handle *dev_handle)
+{
+	struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
+	int i;
+
+	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) ) {
+			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_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+	struct windows_transfer_priv *transfer_priv = (struct windows_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 = winusb_get_valid_interface(transfer->dev_handle);
+	if (current_interface < 0) {
+		if (auto_claim(transfer, &current_interface, USB_API_WINUSB) != LIBUSB_SUCCESS) {
+			return LIBUSB_ERROR_NOT_FOUND;
+		}
+	}
+
+	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;
+	}
+
+	// Sending of set configuration control requests from WinUSB creates issues
+	if ( ((setup->request_type & (0x03 << 5)) == LIBUSB_REQUEST_TYPE_STANDARD)
+	  && (setup->request == LIBUSB_REQUEST_SET_CONFIGURATION) ) {
+		if (setup->value != priv->active_config) {
+			usbi_warn(ctx, "cannot set configuration other than the default one");
+			usbi_free_fd(wfd.fd);
+			return LIBUSB_ERROR_INVALID_PARAM;
+		}
+		wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
+		wfd.overlapped->InternalHigh = 0;
+	} else {
+		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 = (struct windows_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 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;
+
+	wfd = usbi_create_fd(winusb_handle, IS_XFERIN(transfer) ? _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 (IS_XFERIN(transfer)) {
+		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 (IS_EPIN(priv->usb_interface[i].endpoint[j])
+				  && (!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;
+}
+
+
+/*
+ * 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;
+
+	for (i=0; i<USB_MAXINTERFACES; i++) {
+		if (priv->usb_interface[i].path != NULL) {
+			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);
+}

+ 608 - 0
compat/libusb-1.0/libusb/os/windows_usb.h

@@ -0,0 +1,608 @@
+/*
+ * 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)
+static 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_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
+
+// 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_MAX         4
+
+#define CLASS_GUID_UNSUPPORTED      GUID_NULL
+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
+ */
+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;
+	} usb_interface[USB_MAXINTERFACES];
+	uint8_t composite_api_flags;		// composite devices require additional data
+	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->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;
+	}
+}
+
+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);
+	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];
+	int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
+};
+
+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;
+};
+
+// 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_PREFIXNAME(api, ret, prefixname, name, args)    \
+	typedef ret (api * __dll_##name##_t)args;                 \
+	static __dll_##name##_t prefixname = NULL
+
+#define DLL_LOAD_PREFIXNAME(dll, prefixname, 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; }                                       \
+	}                                                         \
+	prefixname = (__dll_##name##_t)GetProcAddress(h, #name);       \
+	if (prefixname) break;                                         \
+	prefixname = (__dll_##name##_t)GetProcAddress(h, #name "A");   \
+	if (prefixname) break;                                         \
+	prefixname = (__dll_##name##_t)GetProcAddress(h, #name "W");   \
+	if (prefixname) break;                                         \
+	if(ret_on_failure)                                        \
+		return LIBUSB_ERROR_NOT_FOUND;                        \
+	} while(0)
+
+#define DLL_DECLARE(api, ret, name, args)   DLL_DECLARE_PREFIXNAME(api, ret, name, name, args)
+#define DLL_LOAD(dll, name, ret_on_failure) DLL_LOAD_PREFIXNAME(dll, name, name, ret_on_failure)
+#define DLL_DECLARE_PREFIXED(api, ret, prefix, name, args)   DLL_DECLARE_PREFIXNAME(api, ret, prefix##name, name, args)
+#define DLL_LOAD_PREFIXED(dll, prefix, name, ret_on_failure) DLL_LOAD_PREFIXNAME(dll, prefix##name, 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_DESCRIPTOR_FROM_NODE_CONNECTION 260
+#define USB_GET_NODE_CONNECTION_NAME            261
+#define USB_GET_HUB_CAPABILITIES                271
+#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX)
+#define USB_GET_NODE_CONNECTION_INFORMATION_EX  274
+#endif
+#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_EX \
+  CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, 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_EX {
+	ULONG  ConnectionIndex;
+	USB_DEVICE_DESCRIPTOR  DeviceDescriptor;
+	UCHAR  CurrentConfigurationValue;
+	UCHAR  Speed;
+	BOOLEAN  DeviceIsHub;
+	USHORT  DeviceAddress;
+	ULONG  NumberOfOpenPipes;
+	USB_CONNECTION_STATUS  ConnectionStatus;
+//	USB_PIPE_INFO  PipeList[0];
+} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX;
+
+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));

+ 322 - 0
compat/libusb-1.0/libusb/sync.c

@@ -0,0 +1,322 @@
+/*
+ * 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_completed(HANDLE_CTX(dev_handle), &completed);
+		if (r < 0) {
+			if (r == LIBUSB_ERROR_INTERRUPTED)
+				continue;
+			libusb_cancel_transfer(transfer);
+			while (!completed)
+				if (libusb_handle_events_completed(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;
+	case LIBUSB_TRANSFER_OVERFLOW:
+		r = LIBUSB_ERROR_OVERFLOW;
+		break;
+	case LIBUSB_TRANSFER_ERROR:
+	case LIBUSB_TRANSFER_CANCELLED:
+		r = LIBUSB_ERROR_IO;
+		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_completed(HANDLE_CTX(dev_handle), &completed);
+		if (r < 0) {
+			if (r == LIBUSB_ERROR_INTERRUPTED)
+				continue;
+			libusb_cancel_transfer(transfer);
+			while (!completed)
+				if (libusb_handle_events_completed(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;
+	case LIBUSB_TRANSFER_ERROR:
+	case LIBUSB_TRANSFER_CANCELLED:
+		r = LIBUSB_ERROR_IO;
+		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);
+}
+

+ 18 - 0
compat/libusb-1.0/libusb/version.h

@@ -0,0 +1,18 @@
+/* This file is parsed by m4 and windres and RC.EXE so please keep it simple. */
+#ifndef LIBUSB_MAJOR
+#define LIBUSB_MAJOR 1
+#endif
+#ifndef LIBUSB_MINOR
+#define LIBUSB_MINOR 0
+#endif
+#ifndef LIBUSB_MICRO
+#define LIBUSB_MICRO 16
+#endif
+/* LIBUSB_NANO may be used for Windows internal versioning. 0 means unused. */
+#ifndef LIBUSB_NANO
+#define LIBUSB_NANO 0
+#endif
+/* LIBUSB_RC is the release candidate suffix. Should normally be empty. */
+#ifndef LIBUSB_RC
+#define LIBUSB_RC "-rc10"
+#endif

+ 9661 - 0
compat/libusb-1.0/ltmain.sh

@@ -0,0 +1,9661 @@
+
+# libtool (GNU libtool) 2.4.2
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+#       --config             show all configuration variables
+#       --debug              enable verbose shell tracing
+#   -n, --dry-run            display commands without modifying any files
+#       --features           display basic configuration information and exit
+#       --mode=MODE          use operation mode MODE
+#       --preserve-dup-deps  don't remove duplicate dependency libraries
+#       --quiet, --silent    don't print informational messages
+#       --no-quiet, --no-silent
+#                            print informational messages (default)
+#       --no-warn            don't display warning messages
+#       --tag=TAG            use configuration variables from tag TAG
+#   -v, --verbose            print more informational messages than default
+#       --no-verbose         don't print the extra informational messages
+#       --version            print version information
+#   -h, --help, --help-all   print short, long, or detailed help message
+#
+# MODE must be one of the following:
+#
+#         clean              remove files from the build directory
+#         compile            compile a source file into a libtool object
+#         execute            automatically set library path, then run a program
+#         finish             complete the installation of libtool libraries
+#         install            install libraries or executables
+#         link               create a library or an executable
+#         uninstall          remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE.  When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+#         host-triplet:	$host
+#         shell:		$SHELL
+#         compiler:		$LTCC
+#         compiler flags:		$LTCFLAGS
+#         linker:		$LD (gnu? $with_gnu_ld)
+#         $progname:	(GNU libtool) 2.4.2 Debian-2.4.2-1ubuntu1
+#         automake:	$automake_version
+#         autoconf:	$autoconf_version
+#
+# Report bugs to <bug-libtool@gnu.org>.
+# GNU libtool home page: <http://www.gnu.org/software/libtool/>.
+# General help using GNU software: <http://www.gnu.org/gethelp/>.
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION="2.4.2 Debian-2.4.2-1ubuntu1"
+TIMESTAMP=""
+package_revision=1.3337
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# NLS nuisances: We save the old values to restore during execute mode.
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+  eval "if test \"\${$lt_var+set}\" = set; then
+          save_$lt_var=\$$lt_var
+          $lt_var=C
+	  export $lt_var
+	  lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+	  lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+	fi"
+done
+LC_ALL=C
+LANGUAGE=C
+export LANGUAGE LC_ALL
+
+$lt_unset CDPATH
+
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+
+
+: ${CP="cp -f"}
+test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77	  # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" 	$lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+    func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+    if test "X$func_dirname_result" = "X${1}"; then
+      func_dirname_result="${3}"
+    else
+      func_dirname_result="$func_dirname_result${2}"
+    fi
+} # func_dirname may be replaced by extended shell implementation
+
+
+# func_basename file
+func_basename ()
+{
+    func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+} # func_basename may be replaced by extended shell implementation
+
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+    # Extract subdirectory from the argument.
+    func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
+    if test "X$func_dirname_result" = "X${1}"; then
+      func_dirname_result="${3}"
+    else
+      func_dirname_result="$func_dirname_result${2}"
+    fi
+    func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
+} # func_dirname_and_basename may be replaced by extended shell implementation
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+    case ${2} in
+      .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+      *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+    esac
+} # func_stripname may be replaced by extended shell implementation
+
+
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+		s@/\./@/@g
+		t dotsl
+		s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+#             value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+  # Start from root dir and reassemble the path.
+  func_normal_abspath_result=
+  func_normal_abspath_tpath=$1
+  func_normal_abspath_altnamespace=
+  case $func_normal_abspath_tpath in
+    "")
+      # Empty path, that just means $cwd.
+      func_stripname '' '/' "`pwd`"
+      func_normal_abspath_result=$func_stripname_result
+      return
+    ;;
+    # The next three entries are used to spot a run of precisely
+    # two leading slashes without using negated character classes;
+    # we take advantage of case's first-match behaviour.
+    ///*)
+      # Unusual form of absolute path, do nothing.
+    ;;
+    //*)
+      # Not necessarily an ordinary path; POSIX reserves leading '//'
+      # and for example Cygwin uses it to access remote file shares
+      # over CIFS/SMB, so we conserve a leading double slash if found.
+      func_normal_abspath_altnamespace=/
+    ;;
+    /*)
+      # Absolute path, do nothing.
+    ;;
+    *)
+      # Relative path, prepend $cwd.
+      func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+    ;;
+  esac
+  # Cancel out all the simple stuff to save iterations.  We also want
+  # the path to end with a slash for ease of parsing, so make sure
+  # there is one (and only one) here.
+  func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+  while :; do
+    # Processed it all yet?
+    if test "$func_normal_abspath_tpath" = / ; then
+      # If we ascended to the root using ".." the result may be empty now.
+      if test -z "$func_normal_abspath_result" ; then
+        func_normal_abspath_result=/
+      fi
+      break
+    fi
+    func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcar"`
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcdr"`
+    # Figure out what to do with it
+    case $func_normal_abspath_tcomponent in
+      "")
+        # Trailing empty path component, ignore it.
+      ;;
+      ..)
+        # Parent dir; strip last assembled component from result.
+        func_dirname "$func_normal_abspath_result"
+        func_normal_abspath_result=$func_dirname_result
+      ;;
+      *)
+        # Actual path component, append it.
+        func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+      ;;
+    esac
+  done
+  # Restore leading double-slash if one was found on entry.
+  func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+#             value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+  func_relative_path_result=
+  func_normal_abspath "$1"
+  func_relative_path_tlibdir=$func_normal_abspath_result
+  func_normal_abspath "$2"
+  func_relative_path_tbindir=$func_normal_abspath_result
+
+  # Ascend the tree starting from libdir
+  while :; do
+    # check if we have found a prefix of bindir
+    case $func_relative_path_tbindir in
+      $func_relative_path_tlibdir)
+        # found an exact match
+        func_relative_path_tcancelled=
+        break
+        ;;
+      $func_relative_path_tlibdir*)
+        # found a matching prefix
+        func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+        func_relative_path_tcancelled=$func_stripname_result
+        if test -z "$func_relative_path_result"; then
+          func_relative_path_result=.
+        fi
+        break
+        ;;
+      *)
+        func_dirname $func_relative_path_tlibdir
+        func_relative_path_tlibdir=${func_dirname_result}
+        if test "x$func_relative_path_tlibdir" = x ; then
+          # Have to descend all the way to the root!
+          func_relative_path_result=../$func_relative_path_result
+          func_relative_path_tcancelled=$func_relative_path_tbindir
+          break
+        fi
+        func_relative_path_result=../$func_relative_path_result
+        ;;
+    esac
+  done
+
+  # Now calculate path; take care to avoid doubling-up slashes.
+  func_stripname '' '/' "$func_relative_path_result"
+  func_relative_path_result=$func_stripname_result
+  func_stripname '/' '/' "$func_relative_path_tcancelled"
+  if test "x$func_stripname_result" != x ; then
+    func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+  fi
+
+  # Normalisation. If bindir is libdir, return empty string,
+  # else relative path ending with a slash; either way, target
+  # file name can be directly appended.
+  if test ! -z "$func_relative_path_result"; then
+    func_stripname './' '' "$func_relative_path_result/"
+    func_relative_path_result=$func_stripname_result
+  fi
+}
+
+# The name of this program:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+  [\\/]*|[A-Za-z]:\\*) ;;
+  *[\\/]*)
+     progdir=$func_dirname_result
+     progdir=`cd "$progdir" && pwd`
+     progpath="$progdir/$progname"
+     ;;
+  *)
+     save_IFS="$IFS"
+     IFS=${PATH_SEPARATOR-:}
+     for progdir in $PATH; do
+       IFS="$save_IFS"
+       test -x "$progdir/$progname" && break
+     done
+     IFS="$save_IFS"
+     test -n "$progdir" || progdir=`pwd`
+     progpath="$progdir/$progname"
+     ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s,[].[^$\\*\/],\\&,g'
+
+# Sed substitution that converts a w32 file name or path
+# which contains forward slashes, into one that contains
+# (escaped) backslashes.  A very naive implementation.
+lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same.  If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'.  `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+  s/$bs4/&\\
+/g
+  s/^$bs2$dollar/$bs&/
+  s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+  s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+    $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+    $opt_verbose && func_echo ${1+"$@"}
+
+    # A bug in bash halts the script if the last line of a function
+    # fails when set -e is in force, so we need another command to
+    # work around that:
+    :
+}
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+    $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+    $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+
+    # bash bug again:
+    :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+    func_error ${1+"$@"}
+    exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+    func_error ${1+"$@"}
+    func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information."  ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+    $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+    my_directory_path="$1"
+    my_dir_list=
+
+    if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+      # Protect directory names starting with `-'
+      case $my_directory_path in
+        -*) my_directory_path="./$my_directory_path" ;;
+      esac
+
+      # While some portion of DIR does not yet exist...
+      while test ! -d "$my_directory_path"; do
+        # ...make a list in topmost first order.  Use a colon delimited
+	# list incase some portion of path contains whitespace.
+        my_dir_list="$my_directory_path:$my_dir_list"
+
+        # If the last portion added has no slash in it, the list is done
+        case $my_directory_path in */*) ;; *) break ;; esac
+
+        # ...otherwise throw away the child directory and loop
+        my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+      done
+      my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+
+      save_mkdir_p_IFS="$IFS"; IFS=':'
+      for my_dir in $my_dir_list; do
+	IFS="$save_mkdir_p_IFS"
+        # mkdir can fail with a `File exist' error if two processes
+        # try to create one of the directories concurrently.  Don't
+        # stop in that case!
+        $MKDIR "$my_dir" 2>/dev/null || :
+      done
+      IFS="$save_mkdir_p_IFS"
+
+      # Bail out if we (or some other process) failed to create a directory.
+      test -d "$my_directory_path" || \
+        func_fatal_error "Failed to create \`$1'"
+    fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible.  If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+    my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+    if test "$opt_dry_run" = ":"; then
+      # Return a directory name, but don't create it in dry-run mode
+      my_tmpdir="${my_template}-$$"
+    else
+
+      # If mktemp works, use that first and foremost
+      my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+      if test ! -d "$my_tmpdir"; then
+        # Failing that, at least try and use $RANDOM to avoid a race
+        my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+        save_mktempdir_umask=`umask`
+        umask 0077
+        $MKDIR "$my_tmpdir"
+        umask $save_mktempdir_umask
+      fi
+
+      # If we're not in dry-run mode, bomb out on failure
+      test -d "$my_tmpdir" || \
+        func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+    fi
+
+    $ECHO "$my_tmpdir"
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+    case $1 in
+      *[\\\`\"\$]*)
+	func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
+      *)
+        func_quote_for_eval_unquoted_result="$1" ;;
+    esac
+
+    case $func_quote_for_eval_unquoted_result in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting, command substitution and and variable
+      # expansion for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+        ;;
+      *)
+        func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+    esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    case $1 in
+      *[\\\`\"]*)
+	my_arg=`$ECHO "$1" | $SED \
+	    -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        my_arg="$1" ;;
+    esac
+
+    case $my_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        my_arg="\"$my_arg\""
+        ;;
+    esac
+
+    func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$my_cmd"
+      my_status=$?
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.  Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$lt_user_locale
+	    $my_cmd"
+      my_status=$?
+      eval "$lt_safe_locale"
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+# func_tr_sh
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result.  All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+  case $1 in
+  [0-9]* | *[!a-zA-Z0-9_]*)
+    func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'`
+    ;;
+  * )
+    func_tr_sh_result=$1
+    ;;
+  esac
+}
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+    $opt_debug
+
+    $SED -n '/(C)/!b go
+	:more
+	/\./!{
+	  N
+	  s/\n# / /
+	  b more
+	}
+	:go
+	/^# '$PROGRAM' (GNU /,/# warranty; / {
+        s/^# //
+	s/^# *$//
+        s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+        p
+     }' < "$progpath"
+     exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+    $opt_debug
+
+    $SED -n '/^# Usage:/,/^#  *.*--help/ {
+        s/^# //
+	s/^# *$//
+	s/\$progname/'$progname'/
+	p
+    }' < "$progpath"
+    echo
+    $ECHO "run \`$progname --help | more' for full usage"
+    exit $?
+}
+
+# func_help [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
+func_help ()
+{
+    $opt_debug
+
+    $SED -n '/^# Usage:/,/# Report bugs to/ {
+	:print
+        s/^# //
+	s/^# *$//
+	s*\$progname*'$progname'*
+	s*\$host*'"$host"'*
+	s*\$SHELL*'"$SHELL"'*
+	s*\$LTCC*'"$LTCC"'*
+	s*\$LTCFLAGS*'"$LTCFLAGS"'*
+	s*\$LD*'"$LD"'*
+	s/\$with_gnu_ld/'"$with_gnu_ld"'/
+	s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/
+	s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/
+	p
+	d
+     }
+     /^# .* home page:/b print
+     /^# General help using/b print
+     ' < "$progpath"
+    ret=$?
+    if test -z "$1"; then
+      exit $ret
+    fi
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+    $opt_debug
+
+    func_error "missing argument for $1."
+    exit_cmd=exit
+}
+
+
+# func_split_short_opt shortopt
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+func_split_short_opt ()
+{
+    my_sed_short_opt='1s/^\(..\).*$/\1/;q'
+    my_sed_short_rest='1s/^..\(.*\)$/\1/;q'
+
+    func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"`
+    func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"`
+} # func_split_short_opt may be replaced by extended shell implementation
+
+
+# func_split_long_opt longopt
+# Set func_split_long_opt_name and func_split_long_opt_arg shell
+# variables after splitting LONGOPT at the `=' sign.
+func_split_long_opt ()
+{
+    my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q'
+    my_sed_long_arg='1s/^--[^=]*=//'
+
+    func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"`
+    func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"`
+} # func_split_long_opt may be replaced by extended shell implementation
+
+exit_cmd=:
+
+
+
+
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+nonopt=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+    eval "${1}=\$${1}\${2}"
+} # func_append may be replaced by extended shell implementation
+
+# func_append_quoted var value
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+func_append_quoted ()
+{
+    func_quote_for_eval "${2}"
+    eval "${1}=\$${1}\\ \$func_quote_for_eval_result"
+} # func_append_quoted may be replaced by extended shell implementation
+
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+    func_arith_result=`expr "${@}"`
+} # func_arith may be replaced by extended shell implementation
+
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+    func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len`
+} # func_len may be replaced by extended shell implementation
+
+
+# func_lo2o object
+func_lo2o ()
+{
+    func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+} # func_lo2o may be replaced by extended shell implementation
+
+
+# func_xform libobj-or-source
+func_xform ()
+{
+    func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
+} # func_xform may be replaced by extended shell implementation
+
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+    func_error ${1+"$@"}
+    func_error "See the $PACKAGE documentation for more information."
+    func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+    re_begincf='^# ### BEGIN LIBTOOL'
+    re_endcf='^# ### END LIBTOOL'
+
+    # Default configuration.
+    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+    done
+
+    exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+    echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+
+    exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+  # Global variable:
+  tagname="$1"
+
+  re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+  re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+  sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+  # Validate tagname.
+  case $tagname in
+    *[!-_A-Za-z0-9,/]*)
+      func_fatal_error "invalid tag name: $tagname"
+      ;;
+  esac
+
+  # Don't test for the "default" C tag, as we know it's
+  # there but not specially marked.
+  case $tagname in
+    CC) ;;
+    *)
+      if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+	taglist="$taglist $tagname"
+
+	# Evaluate the configuration.  Be careful to quote the path
+	# and the sed script, to avoid splitting on whitespace, but
+	# also don't use non-portable quotes within backquotes within
+	# quotes we have to do it in 2 steps:
+	extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+	eval "$extractedcf"
+      else
+	func_error "ignoring unknown tag $tagname"
+      fi
+      ;;
+  esac
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+  if test "$package_revision" != "$macro_revision"; then
+    if test "$VERSION" != "$macro_version"; then
+      if test -z "$macro_version"; then
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      else
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      fi
+    else
+      cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+    fi
+
+    exit $EXIT_MISMATCH
+  fi
+}
+
+
+# Shorthand for --mode=foo, only valid as the first argument
+case $1 in
+clean|clea|cle|cl)
+  shift; set dummy --mode clean ${1+"$@"}; shift
+  ;;
+compile|compil|compi|comp|com|co|c)
+  shift; set dummy --mode compile ${1+"$@"}; shift
+  ;;
+execute|execut|execu|exec|exe|ex|e)
+  shift; set dummy --mode execute ${1+"$@"}; shift
+  ;;
+finish|finis|fini|fin|fi|f)
+  shift; set dummy --mode finish ${1+"$@"}; shift
+  ;;
+install|instal|insta|inst|ins|in|i)
+  shift; set dummy --mode install ${1+"$@"}; shift
+  ;;
+link|lin|li|l)
+  shift; set dummy --mode link ${1+"$@"}; shift
+  ;;
+uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+  shift; set dummy --mode uninstall ${1+"$@"}; shift
+  ;;
+esac
+
+
+
+# Option defaults:
+opt_debug=:
+opt_dry_run=false
+opt_config=false
+opt_preserve_dup_deps=false
+opt_features=false
+opt_finish=false
+opt_help=false
+opt_help_all=false
+opt_silent=:
+opt_warning=:
+opt_verbose=:
+opt_silent=false
+opt_verbose=false
+
+
+# Parse options once, thoroughly.  This comes as soon as possible in the
+# script to make things like `--version' happen as quickly as we can.
+{
+  # this just eases exit handling
+  while test $# -gt 0; do
+    opt="$1"
+    shift
+    case $opt in
+      --debug|-x)	opt_debug='set -x'
+			func_echo "enabling shell trace mode"
+			$opt_debug
+			;;
+      --dry-run|--dryrun|-n)
+			opt_dry_run=:
+			;;
+      --config)
+			opt_config=:
+func_config
+			;;
+      --dlopen|-dlopen)
+			optarg="$1"
+			opt_dlopen="${opt_dlopen+$opt_dlopen
+}$optarg"
+			shift
+			;;
+      --preserve-dup-deps)
+			opt_preserve_dup_deps=:
+			;;
+      --features)
+			opt_features=:
+func_features
+			;;
+      --finish)
+			opt_finish=:
+set dummy --mode finish ${1+"$@"}; shift
+			;;
+      --help)
+			opt_help=:
+			;;
+      --help-all)
+			opt_help_all=:
+opt_help=': help-all'
+			;;
+      --mode)
+			test $# = 0 && func_missing_arg $opt && break
+			optarg="$1"
+			opt_mode="$optarg"
+case $optarg in
+  # Valid mode arguments:
+  clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+  # Catch anything else as an error
+  *) func_error "invalid argument for $opt"
+     exit_cmd=exit
+     break
+     ;;
+esac
+			shift
+			;;
+      --no-silent|--no-quiet)
+			opt_silent=false
+func_append preserve_args " $opt"
+			;;
+      --no-warning|--no-warn)
+			opt_warning=false
+func_append preserve_args " $opt"
+			;;
+      --no-verbose)
+			opt_verbose=false
+func_append preserve_args " $opt"
+			;;
+      --silent|--quiet)
+			opt_silent=:
+func_append preserve_args " $opt"
+        opt_verbose=false
+			;;
+      --verbose|-v)
+			opt_verbose=:
+func_append preserve_args " $opt"
+opt_silent=false
+			;;
+      --tag)
+			test $# = 0 && func_missing_arg $opt && break
+			optarg="$1"
+			opt_tag="$optarg"
+func_append preserve_args " $opt $optarg"
+func_enable_tag "$optarg"
+			shift
+			;;
+
+      -\?|-h)		func_usage				;;
+      --help)		func_help				;;
+      --version)	func_version				;;
+
+      # Separate optargs to long options:
+      --*=*)
+			func_split_long_opt "$opt"
+			set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"}
+			shift
+			;;
+
+      # Separate non-argument short options:
+      -\?*|-h*|-n*|-v*)
+			func_split_short_opt "$opt"
+			set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"}
+			shift
+			;;
+
+      --)		break					;;
+      -*)		func_fatal_help "unrecognized option \`$opt'" ;;
+      *)		set dummy "$opt" ${1+"$@"};	shift; break  ;;
+    esac
+  done
+
+  # Validate options:
+
+  # save first non-option argument
+  if test "$#" -gt 0; then
+    nonopt="$opt"
+    shift
+  fi
+
+  # preserve --debug
+  test "$opt_debug" = : || func_append preserve_args " --debug"
+
+  case $host in
+    *cygwin* | *mingw* | *pw32* | *cegcc*)
+      # don't eliminate duplications in $postdeps and $predeps
+      opt_duplicate_compiler_generated_deps=:
+      ;;
+    *)
+      opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+      ;;
+  esac
+
+  $opt_help || {
+    # Sanity checks first:
+    func_check_version_match
+
+    if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+      func_fatal_configuration "not configured to build any kind of library"
+    fi
+
+    # Darwin sucks
+    eval std_shrext=\"$shrext_cmds\"
+
+    # Only execute mode is allowed to have -dlopen flags.
+    if test -n "$opt_dlopen" && test "$opt_mode" != execute; then
+      func_error "unrecognized option \`-dlopen'"
+      $ECHO "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    # Change the help message to a mode-specific one.
+    generic_help="$help"
+    help="Try \`$progname --help --mode=$opt_mode' for more information."
+  }
+
+
+  # Bail if the options were screwed
+  $exit_cmd $EXIT_FAILURE
+}
+
+
+
+
+## ----------- ##
+##    Main.    ##
+## ----------- ##
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+    test -f "$1" &&
+      $SED -e 4q "$1" 2>/dev/null \
+        | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs.  To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway.  Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+    lalib_p=no
+    if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+	for lalib_p_l in 1 2 3 4
+	do
+	    read lalib_p_line
+	    case "$lalib_p_line" in
+		\#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+	    esac
+	done
+	exec 0<&5 5<&-
+    fi
+    test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+    func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+    func_ltwrapper_exec_suffix=
+    case $1 in
+    *.exe) ;;
+    *) func_ltwrapper_exec_suffix=.exe ;;
+    esac
+    $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+    func_dirname_and_basename "$1" "" "."
+    func_stripname '' '.exe' "$func_basename_result"
+    func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+    func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+    $opt_debug
+    save_ifs=$IFS; IFS='~'
+    for cmd in $1; do
+      IFS=$save_ifs
+      eval cmd=\"$cmd\"
+      func_show_eval "$cmd" "${2-:}"
+    done
+    IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)!  Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+    $opt_debug
+    case $1 in
+    */* | *\\*)	. "$1" ;;
+    *)		. "./$1" ;;
+    esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot.  Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+  func_resolve_sysroot_result=$1
+  case $func_resolve_sysroot_result in
+  =*)
+    func_stripname '=' '' "$func_resolve_sysroot_result"
+    func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+    ;;
+  esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+  case "$lt_sysroot:$1" in
+  ?*:"$lt_sysroot"*)
+    func_stripname "$lt_sysroot" '' "$1"
+    func_replace_sysroot_result="=$func_stripname_result"
+    ;;
+  *)
+    # Including no sysroot.
+    func_replace_sysroot_result=$1
+    ;;
+  esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    $opt_debug
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+	func_append_quoted CC_quoted "$arg"
+      done
+      CC_expanded=`func_echo_all $CC`
+      CC_quoted_expanded=`func_echo_all $CC_quoted`
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+	for z in $available_tags; do
+	  if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+	    # Evaluate the configuration.
+	    eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+	    CC_quoted=
+	    for arg in $CC; do
+	      # Double-quote args containing other shell metacharacters.
+	      func_append_quoted CC_quoted "$arg"
+	    done
+	    CC_expanded=`func_echo_all $CC`
+	    CC_quoted_expanded=`func_echo_all $CC_quoted`
+	    case "$@ " in
+	    " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+	    " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+	      # The compiler in the base compile command matches
+	      # the one in the tagged configuration.
+	      # Assume this is the tagged configuration we want.
+	      tagname=$z
+	      break
+	      ;;
+	    esac
+	  fi
+	done
+	# If $tagname still isn't set, then no tagged configuration
+	# was found and let the user know that the "--tag" command
+	# line option must be used.
+	if test -z "$tagname"; then
+	  func_echo "unable to infer tagged configuration"
+	  func_fatal_error "specify a tag with \`--tag'"
+#	else
+#	  func_verbose "using $tagname tagged configuration"
+	fi
+	;;
+      esac
+    fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+    write_libobj=${1}
+    if test "$build_libtool_libs" = yes; then
+      write_lobj=\'${2}\'
+    else
+      write_lobj=none
+    fi
+
+    if test "$build_old_libs" = yes; then
+      write_oldobj=\'${3}\'
+    else
+      write_oldobj=none
+    fi
+
+    $opt_dry_run || {
+      cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+      $MV "${write_libobj}T" "${write_libobj}"
+    }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+  $opt_debug
+  func_convert_core_file_wine_to_w32_result="$1"
+  if test -n "$1"; then
+    # Unfortunately, winepath does not exit with a non-zero error code, so we
+    # are forced to check the contents of stdout. On the other hand, if the
+    # command is not found, the shell will set an exit code of 127 and print
+    # *an error message* to stdout. So we must check for both error code of
+    # zero AND non-empty stdout, which explains the odd construction:
+    func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+    if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then
+      func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+        $SED -e "$lt_sed_naive_backslashify"`
+    else
+      func_convert_core_file_wine_to_w32_result=
+    fi
+  fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+  $opt_debug
+  # unfortunately, winepath doesn't convert paths, only file names
+  func_convert_core_path_wine_to_w32_result=""
+  if test -n "$1"; then
+    oldIFS=$IFS
+    IFS=:
+    for func_convert_core_path_wine_to_w32_f in $1; do
+      IFS=$oldIFS
+      func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+      if test -n "$func_convert_core_file_wine_to_w32_result" ; then
+        if test -z "$func_convert_core_path_wine_to_w32_result"; then
+          func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result"
+        else
+          func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+        fi
+      fi
+    done
+    IFS=$oldIFS
+  fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+  $opt_debug
+  if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+    func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+    if test "$?" -ne 0; then
+      # on failure, ensure result is empty
+      func_cygpath_result=
+    fi
+  else
+    func_cygpath_result=
+    func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'"
+  fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format.  Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+  $opt_debug
+  # awkward: cmd appends spaces to result
+  func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+    $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+  $opt_debug
+  if test -z "$2" && test -n "$1" ; then
+    func_error "Could not determine host file name corresponding to"
+    func_error "  \`$1'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback:
+    func_to_host_file_result="$1"
+  fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+  $opt_debug
+  if test -z "$4" && test -n "$3"; then
+    func_error "Could not determine the host path corresponding to"
+    func_error "  \`$3'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback.  This is a deliberately simplistic "conversion" and
+    # should not be "improved".  See libtool.info.
+    if test "x$1" != "x$2"; then
+      lt_replace_pathsep_chars="s|$1|$2|g"
+      func_to_host_path_result=`echo "$3" |
+        $SED -e "$lt_replace_pathsep_chars"`
+    else
+      func_to_host_path_result="$3"
+    fi
+  fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+  $opt_debug
+  case $4 in
+  $1 ) func_to_host_path_result="$3$func_to_host_path_result"
+    ;;
+  esac
+  case $4 in
+  $2 ) func_append func_to_host_path_result "$3"
+    ;;
+  esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via `$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+  $opt_debug
+  $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result.  If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+  $opt_debug
+  case ,$2, in
+    *,"$to_tool_file_cmd",*)
+      func_to_tool_file_result=$1
+      ;;
+    *)
+      $to_tool_file_cmd "$1"
+      func_to_tool_file_result=$func_to_host_file_result
+      ;;
+  esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+  func_to_host_file_result="$1"
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_to_host_file_result="$func_convert_core_msys_to_w32_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+    # LT_CYGPATH in this case.
+    func_to_host_file_result=`cygpath -m "$1"`
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format.  Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_file_wine_to_w32 "$1"
+    func_to_host_file_result="$func_convert_core_file_wine_to_w32_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_msys_to_w32_result"
+    func_to_host_file_result="$func_cygpath_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format.  Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set.  Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+    func_convert_core_file_wine_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+    func_to_host_file_result="$func_cygpath_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via `$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format.  If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+#   file name conversion function    : func_convert_file_X_to_Y ()
+#   path conversion function         : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same.  If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+  $opt_debug
+  if test -z "$to_host_path_cmd"; then
+    func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+    to_host_path_cmd="func_convert_path_${func_stripname_result}"
+  fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+  $opt_debug
+  func_init_to_host_path_cmd
+  $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+  func_to_host_path_result="$1"
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from ARG.  MSYS
+    # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+    # and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result="$func_convert_core_msys_to_w32_result"
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format.  Requires a wine environment and
+# a working winepath.  Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result="$func_convert_core_path_wine_to_w32_result"
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+    func_to_host_path_result="$func_cygpath_result"
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format.  Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set.  Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+    func_to_host_path_result="$func_cygpath_result"
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+    $opt_debug
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+    pie_flag=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+	# do not "continue".  Instead, add this to base_compile
+	lastarg="$arg"
+	arg_mode=normal
+	;;
+
+      target )
+	libobj="$arg"
+	arg_mode=normal
+	continue
+	;;
+
+      normal )
+	# Accept any command-line options.
+	case $arg in
+	-o)
+	  test -n "$libobj" && \
+	    func_fatal_error "you cannot specify \`-o' more than once"
+	  arg_mode=target
+	  continue
+	  ;;
+
+	-pie | -fpie | -fPIE)
+          func_append pie_flag " $arg"
+	  continue
+	  ;;
+
+	-shared | -static | -prefer-pic | -prefer-non-pic)
+	  func_append later " $arg"
+	  continue
+	  ;;
+
+	-no-suppress)
+	  suppress_opt=no
+	  continue
+	  ;;
+
+	-Xcompiler)
+	  arg_mode=arg  #  the next one goes into the "base_compile" arg list
+	  continue      #  The current "srcfile" will either be retained or
+	  ;;            #  replaced later.  I would guess that would be a bug.
+
+	-Wc,*)
+	  func_stripname '-Wc,' '' "$arg"
+	  args=$func_stripname_result
+	  lastarg=
+	  save_ifs="$IFS"; IFS=','
+	  for arg in $args; do
+	    IFS="$save_ifs"
+	    func_append_quoted lastarg "$arg"
+	  done
+	  IFS="$save_ifs"
+	  func_stripname ' ' '' "$lastarg"
+	  lastarg=$func_stripname_result
+
+	  # Add the arguments to base_compile.
+	  func_append base_compile " $lastarg"
+	  continue
+	  ;;
+
+	*)
+	  # Accept the current argument as the source file.
+	  # The previous "srcfile" becomes the current argument.
+	  #
+	  lastarg="$srcfile"
+	  srcfile="$arg"
+	  ;;
+	esac  #  case $arg
+	;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      func_append_quoted base_compile "$lastarg"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      func_fatal_error "you must specify an argument for -Xcompile"
+      ;;
+    target)
+      func_fatal_error "you must specify a target with \`-o'"
+      ;;
+    *)
+      # Get the name of the library object.
+      test -z "$libobj" && {
+	func_basename "$srcfile"
+	libobj="$func_basename_result"
+      }
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    case $libobj in
+    *.[cCFSifmso] | \
+    *.ada | *.adb | *.ads | *.asm | \
+    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+    *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+      func_xform "$libobj"
+      libobj=$func_xform_result
+      ;;
+    esac
+
+    case $libobj in
+    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+    *)
+      func_fatal_error "cannot determine name of library object from \`$libobj'"
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	continue
+	;;
+
+      -static)
+	build_libtool_libs=no
+	build_old_libs=yes
+	continue
+	;;
+
+      -prefer-pic)
+	pic_mode=yes
+	continue
+	;;
+
+      -prefer-non-pic)
+	pic_mode=no
+	continue
+	;;
+      esac
+    done
+
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
+      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'	 &()|`$[]' \
+      && func_warning "libobj name \`$libobj' may not contain shell special characters."
+    func_dirname_and_basename "$obj" "/" ""
+    objname="$func_basename_result"
+    xdir="$func_dirname_result"
+    lobj=${xdir}$objdir/$objname
+
+    test -z "$base_compile" && \
+      func_fatal_help "you must specify a compilation command"
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2* | cegcc*)
+      pic_mode=default
+      ;;
+    esac
+    if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test "$compiler_c_o" = no; then
+      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
+      lockfile="$output_obj.lock"
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test "$need_locks" = yes; then
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    elif test "$need_locks" = warn; then
+      if test -f "$lockfile"; then
+	$ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+      func_append removelist " $output_obj"
+      $ECHO "$srcfile" > "$lockfile"
+    fi
+
+    $opt_dry_run || $RM $removelist
+    func_append removelist " $lockfile"
+    trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+    func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+    srcfile=$func_to_tool_file_result
+    func_quote_for_eval "$srcfile"
+    qsrcfile=$func_quote_for_eval_result
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test "$pic_mode" != no; then
+	command="$base_compile $qsrcfile $pic_flag"
+      else
+	# Don't build PIC code
+	command="$base_compile $qsrcfile"
+      fi
+
+      func_mkdir_p "$xdir$objdir"
+
+      if test -z "$output_obj"; then
+	# Place PIC objects in $objdir
+	func_append command " -o $lobj"
+      fi
+
+      func_show_eval_locale "$command"	\
+          'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+	func_show_eval '$MV "$output_obj" "$lobj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+
+      # Allow error messages only from the first compilation.
+      if test "$suppress_opt" = yes; then
+	suppress_output=' >/dev/null 2>&1'
+      fi
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      if test "$pic_mode" != yes; then
+	# Don't build PIC code
+	command="$base_compile $qsrcfile$pie_flag"
+      else
+	command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test "$compiler_c_o" = yes; then
+	func_append command " -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      func_append command "$suppress_output"
+      func_show_eval_locale "$command" \
+        '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+	func_show_eval '$MV "$output_obj" "$obj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+    fi
+
+    $opt_dry_run || {
+      func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+      # Unlock the critical section if it was locked
+      if test "$need_locks" != no; then
+	removelist=$lockfile
+        $RM "$lockfile"
+      fi
+    }
+
+    exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+  test "$opt_mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+    # We need to display help for each of the modes.
+    case $opt_mode in
+      "")
+        # Generic help is extracted from the usage comments
+        # at the start of this file.
+        func_help
+        ;;
+
+      clean)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      compile)
+      $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -no-suppress      do not suppress compiler output for multiple passes
+  -prefer-pic       try to build PIC objects only
+  -prefer-non-pic   try to build non-PIC objects only
+  -shared           do not build a \`.o' file suitable for static linking
+  -static           only build a \`.o' file suitable for static linking
+  -Wc,FLAG          pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+        ;;
+
+      execute)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+        ;;
+
+      finish)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+        ;;
+
+      install)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+  -inst-prefix-dir PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+        ;;
+
+      link)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -bindir BINDIR    specify path to binaries directory (for systems where
+                    libraries must be found in the PATH setting at runtime)
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  Use a list of object files found in FILE to specify objects
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -shared           only do dynamic linking of libtool libraries
+  -shrext SUFFIX    override the standard shared library file extension
+  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-libtool-libs
+                    do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+  -weak LIBNAME     declare that the target provides the LIBNAME interface
+  -Wc,FLAG
+  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
+  -Wl,FLAG
+  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
+  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+        ;;
+
+      uninstall)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      *)
+        func_fatal_help "invalid operation mode \`$opt_mode'"
+        ;;
+    esac
+
+    echo
+    $ECHO "Try \`$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+  if test "$opt_help" = :; then
+    func_mode_help
+  else
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	func_mode_help
+      done
+    } | sed -n '1p; 2,$s/^Usage:/  or: /p'
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	echo
+	func_mode_help
+      done
+    } |
+    sed '1d
+      /^When reporting/,/^Report/{
+	H
+	d
+      }
+      $x
+      /information about other modes/d
+      /more detailed .*MODE/d
+      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+  fi
+  exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+    $opt_debug
+    # The first argument is the command name.
+    cmd="$nonopt"
+    test -z "$cmd" && \
+      func_fatal_help "you must specify a COMMAND"
+
+    # Handle -dlopen flags immediately.
+    for file in $opt_dlopen; do
+      test -f "$file" \
+	|| func_fatal_help "\`$file' is not a file"
+
+      dir=
+      case $file in
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+	# Read the libtool library.
+	dlname=
+	library_names=
+	func_source "$file"
+
+	# Skip this library if it cannot be dlopened.
+	if test -z "$dlname"; then
+	  # Warn if it was a shared library.
+	  test -n "$library_names" && \
+	    func_warning "\`$file' was not linked with \`-export-dynamic'"
+	  continue
+	fi
+
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+
+	if test -f "$dir/$objdir/$dlname"; then
+	  func_append dir "/$objdir"
+	else
+	  if test ! -f "$dir/$dlname"; then
+	    func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+	  fi
+	fi
+	;;
+
+      *.lo)
+	# Just add the directory containing the .lo file.
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+	;;
+
+      *)
+	func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+	continue
+	;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+	eval "$shlibpath_var=\"\$dir\""
+      else
+	eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -* | *.la | *.lo ) ;;
+      *)
+	# Do a test to see if this is really a libtool program.
+	if func_ltwrapper_script_p "$file"; then
+	  func_source "$file"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	elif func_ltwrapper_executable_p "$file"; then
+	  func_ltwrapper_scriptname "$file"
+	  func_source "$func_ltwrapper_scriptname_result"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	fi
+	;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      func_append_quoted args "$file"
+    done
+
+    if test "X$opt_dry_run" = Xfalse; then
+      if test -n "$shlibpath_var"; then
+	# Export the shlibpath_var.
+	eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+      do
+	eval "if test \"\${save_$lt_var+set}\" = set; then
+                $lt_var=\$save_$lt_var; export $lt_var
+	      else
+		$lt_unset $lt_var
+	      fi"
+      done
+
+      # Now prepare to actually exec the command.
+      exec_cmd="\$cmd$args"
+    else
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+	eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+	echo "export $shlibpath_var"
+      fi
+      $ECHO "$cmd$args"
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$opt_mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+    $opt_debug
+    libs=
+    libdirs=
+    admincmds=
+
+    for opt in "$nonopt" ${1+"$@"}
+    do
+      if test -d "$opt"; then
+	func_append libdirs " $opt"
+
+      elif test -f "$opt"; then
+	if func_lalib_unsafe_p "$opt"; then
+	  func_append libs " $opt"
+	else
+	  func_warning "\`$opt' is not a valid libtool archive"
+	fi
+
+      else
+	func_fatal_error "invalid argument \`$opt'"
+      fi
+    done
+
+    if test -n "$libs"; then
+      if test -n "$lt_sysroot"; then
+        sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+        sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+      else
+        sysroot_cmd=
+      fi
+
+      # Remove sysroot references
+      if $opt_dry_run; then
+        for lib in $libs; do
+          echo "removing references to $lt_sysroot and \`=' prefixes from $lib"
+        done
+      else
+        tmpdir=`func_mktempdir`
+        for lib in $libs; do
+	  sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+	    > $tmpdir/tmp-la
+	  mv -f $tmpdir/tmp-la $lib
+	done
+        ${RM}r "$tmpdir"
+      fi
+    fi
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for libdir in $libdirs; do
+	if test -n "$finish_cmds"; then
+	  # Do each command in the finish commands.
+	  func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+	fi
+	if test -n "$finish_eval"; then
+	  # Do the single finish_eval.
+	  eval cmds=\"$finish_eval\"
+	  $opt_dry_run || eval "$cmds" || func_append admincmds "
+       $cmds"
+	fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    $opt_silent && exit $EXIT_SUCCESS
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      echo "----------------------------------------------------------------------"
+      echo "Libraries have been installed in:"
+      for libdir in $libdirs; do
+	$ECHO "   $libdir"
+      done
+      echo
+      echo "If you ever happen to want to link against installed libraries"
+      echo "in a given directory, LIBDIR, you must either use libtool, and"
+      echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+      echo "flag during linking and do at least one of the following:"
+      if test -n "$shlibpath_var"; then
+	echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+	echo "     during execution"
+      fi
+      if test -n "$runpath_var"; then
+	echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+	echo "     during linking"
+      fi
+      if test -n "$hardcode_libdir_flag_spec"; then
+	libdir=LIBDIR
+	eval flag=\"$hardcode_libdir_flag_spec\"
+
+	$ECHO "   - use the \`$flag' linker flag"
+      fi
+      if test -n "$admincmds"; then
+	$ECHO "   - have your system administrator run these commands:$admincmds"
+      fi
+      if test -f /etc/ld.so.conf; then
+	echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+      fi
+      echo
+
+      echo "See any operating system documentation about shared libraries for"
+      case $host in
+	solaris2.[6789]|solaris2.1[0-9])
+	  echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+	  echo "pages."
+	  ;;
+	*)
+	  echo "more information, such as the ld(1) and ld.so(8) manual pages."
+	  ;;
+      esac
+      echo "----------------------------------------------------------------------"
+    fi
+    exit $EXIT_SUCCESS
+}
+
+test "$opt_mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+    $opt_debug
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+       # Allow the use of GNU shtool's install command.
+       case $nonopt in *shtool*) :;; *) false;; esac; then
+      # Aesthetically quote it.
+      func_quote_for_eval "$nonopt"
+      install_prog="$func_quote_for_eval_result "
+      arg=$1
+      shift
+    else
+      install_prog=
+      arg=$nonopt
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    func_quote_for_eval "$arg"
+    func_append install_prog "$func_quote_for_eval_result"
+    install_shared_prog=$install_prog
+    case " $install_prog " in
+      *[\\\ /]cp\ *) install_cp=: ;;
+      *) install_cp=false ;;
+    esac
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    no_mode=:
+    for arg
+    do
+      arg2=
+      if test -n "$dest"; then
+	func_append files " $dest"
+	dest=$arg
+	continue
+      fi
+
+      case $arg in
+      -d) isdir=yes ;;
+      -f)
+	if $install_cp; then :; else
+	  prev=$arg
+	fi
+	;;
+      -g | -m | -o)
+	prev=$arg
+	;;
+      -s)
+	stripme=" -s"
+	continue
+	;;
+      -*)
+	;;
+      *)
+	# If the previous option needed an argument, then skip it.
+	if test -n "$prev"; then
+	  if test "x$prev" = x-m && test -n "$install_override_mode"; then
+	    arg2=$install_override_mode
+	    no_mode=false
+	  fi
+	  prev=
+	else
+	  dest=$arg
+	  continue
+	fi
+	;;
+      esac
+
+      # Aesthetically quote the argument.
+      func_quote_for_eval "$arg"
+      func_append install_prog " $func_quote_for_eval_result"
+      if test -n "$arg2"; then
+	func_quote_for_eval "$arg2"
+      fi
+      func_append install_shared_prog " $func_quote_for_eval_result"
+    done
+
+    test -z "$install_prog" && \
+      func_fatal_help "you must specify an install program"
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prev' option requires an argument"
+
+    if test -n "$install_override_mode" && $no_mode; then
+      if $install_cp; then :; else
+	func_quote_for_eval "$install_override_mode"
+	func_append install_shared_prog " -m $func_quote_for_eval_result"
+      fi
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+	func_fatal_help "no file or destination specified"
+      else
+	func_fatal_help "you must specify a destination"
+      fi
+    fi
+
+    # Strip any trailing slash from the destination.
+    func_stripname '' '/' "$dest"
+    dest=$func_stripname_result
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test "$isdir" = yes; then
+      destdir="$dest"
+      destname=
+    else
+      func_dirname_and_basename "$dest" "" "."
+      destdir="$func_dirname_result"
+      destname="$func_basename_result"
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files; shift
+      test "$#" -gt 1 && \
+	func_fatal_help "\`$dest' is not a directory"
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+	case $file in
+	*.lo) ;;
+	*)
+	  func_fatal_help "\`$destdir' must be an absolute directory name"
+	  ;;
+	esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+	# Do the static libraries later.
+	func_append staticlibs " $file"
+	;;
+
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$file' is not a valid libtool archive"
+
+	library_names=
+	old_library=
+	relink_command=
+	func_source "$file"
+
+	# Add the libdir to current_libdirs if it is the destination.
+	if test "X$destdir" = "X$libdir"; then
+	  case "$current_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append current_libdirs " $libdir" ;;
+	  esac
+	else
+	  # Note the libdir as a future libdir.
+	  case "$future_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append future_libdirs " $libdir" ;;
+	  esac
+	fi
+
+	func_dirname "$file" "/" ""
+	dir="$func_dirname_result"
+	func_append dir "$objdir"
+
+	if test -n "$relink_command"; then
+	  # Determine the prefix the user has applied to our future dir.
+	  inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+	  # Don't allow the user to place us outside of our expected
+	  # location b/c this prevents finding dependent libraries that
+	  # are installed to the same prefix.
+	  # At present, this check doesn't affect windows .dll's that
+	  # are installed into $libdir/../bin (currently, that works fine)
+	  # but it's something to keep an eye on.
+	  test "$inst_prefix_dir" = "$destdir" && \
+	    func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+	  if test -n "$inst_prefix_dir"; then
+	    # Stick the inst_prefix_dir data into the link command.
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+	  else
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+	  fi
+
+	  func_warning "relinking \`$file'"
+	  func_show_eval "$relink_command" \
+	    'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+	fi
+
+	# See the names of the shared library.
+	set dummy $library_names; shift
+	if test -n "$1"; then
+	  realname="$1"
+	  shift
+
+	  srcname="$realname"
+	  test -n "$relink_command" && srcname="$realname"T
+
+	  # Install the shared library and build the symlinks.
+	  func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+	      'exit $?'
+	  tstripme="$stripme"
+	  case $host_os in
+	  cygwin* | mingw* | pw32* | cegcc*)
+	    case $realname in
+	    *.dll.a)
+	      tstripme=""
+	      ;;
+	    esac
+	    ;;
+	  esac
+	  if test -n "$tstripme" && test -n "$striplib"; then
+	    func_show_eval "$striplib $destdir/$realname" 'exit $?'
+	  fi
+
+	  if test "$#" -gt 0; then
+	    # Delete the old symlinks, and create new ones.
+	    # Try `ln -sf' first, because the `ln' binary might depend on
+	    # the symlink we replace!  Solaris /bin/ln does not understand -f,
+	    # so we also need to try rm && ln -s.
+	    for linkname
+	    do
+	      test "$linkname" != "$realname" \
+		&& func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+	    done
+	  fi
+
+	  # Do each command in the postinstall commands.
+	  lib="$destdir/$realname"
+	  func_execute_cmds "$postinstall_cmds" 'exit $?'
+	fi
+
+	# Install the pseudo-library for information purposes.
+	func_basename "$file"
+	name="$func_basename_result"
+	instname="$dir/$name"i
+	func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+	# Maybe install the static library, too.
+	test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+	;;
+
+      *.lo)
+	# Install (i.e. copy) a libtool object.
+
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# Deduce the name of the destination old-style object file.
+	case $destfile in
+	*.lo)
+	  func_lo2o "$destfile"
+	  staticdest=$func_lo2o_result
+	  ;;
+	*.$objext)
+	  staticdest="$destfile"
+	  destfile=
+	  ;;
+	*)
+	  func_fatal_help "cannot copy a libtool object to \`$destfile'"
+	  ;;
+	esac
+
+	# Install the libtool object if requested.
+	test -n "$destfile" && \
+	  func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+	# Install the old object if enabled.
+	if test "$build_old_libs" = yes; then
+	  # Deduce the name of the old-style object file.
+	  func_lo2o "$file"
+	  staticobj=$func_lo2o_result
+	  func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+	fi
+	exit $EXIT_SUCCESS
+	;;
+
+      *)
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# If the file is missing, and there is a .exe on the end, strip it
+	# because it is most likely a libtool script we actually want to
+	# install
+	stripped_ext=""
+	case $file in
+	  *.exe)
+	    if test ! -f "$file"; then
+	      func_stripname '' '.exe' "$file"
+	      file=$func_stripname_result
+	      stripped_ext=".exe"
+	    fi
+	    ;;
+	esac
+
+	# Do a test to see if this is really a libtool program.
+	case $host in
+	*cygwin* | *mingw*)
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      wrapper=$func_ltwrapper_scriptname_result
+	    else
+	      func_stripname '' '.exe' "$file"
+	      wrapper=$func_stripname_result
+	    fi
+	    ;;
+	*)
+	    wrapper=$file
+	    ;;
+	esac
+	if func_ltwrapper_script_p "$wrapper"; then
+	  notinst_deplibs=
+	  relink_command=
+
+	  func_source "$wrapper"
+
+	  # Check the variables that should have been set.
+	  test -z "$generated_by_libtool_version" && \
+	    func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+	  finalize=yes
+	  for lib in $notinst_deplibs; do
+	    # Check to see that each library is installed.
+	    libdir=
+	    if test -f "$lib"; then
+	      func_source "$lib"
+	    fi
+	    libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+	    if test -n "$libdir" && test ! -f "$libfile"; then
+	      func_warning "\`$lib' has not been installed in \`$libdir'"
+	      finalize=no
+	    fi
+	  done
+
+	  relink_command=
+	  func_source "$wrapper"
+
+	  outputname=
+	  if test "$fast_install" = no && test -n "$relink_command"; then
+	    $opt_dry_run || {
+	      if test "$finalize" = yes; then
+	        tmpdir=`func_mktempdir`
+		func_basename "$file$stripped_ext"
+		file="$func_basename_result"
+	        outputname="$tmpdir/$file"
+	        # Replace the output file specification.
+	        relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+	        $opt_silent || {
+	          func_quote_for_expand "$relink_command"
+		  eval "func_echo $func_quote_for_expand_result"
+	        }
+	        if eval "$relink_command"; then :
+	          else
+		  func_error "error: relink \`$file' with the above command before installing it"
+		  $opt_dry_run || ${RM}r "$tmpdir"
+		  continue
+	        fi
+	        file="$outputname"
+	      else
+	        func_warning "cannot relink \`$file'"
+	      fi
+	    }
+	  else
+	    # Install the binary that we compiled earlier.
+	    file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+	  fi
+	fi
+
+	# remove .exe since cygwin /usr/bin/install will append another
+	# one anyway
+	case $install_prog,$host in
+	*/usr/bin/install*,*cygwin*)
+	  case $file:$destfile in
+	  *.exe:*.exe)
+	    # this is ok
+	    ;;
+	  *.exe:*)
+	    destfile=$destfile.exe
+	    ;;
+	  *:*.exe)
+	    func_stripname '' '.exe' "$destfile"
+	    destfile=$func_stripname_result
+	    ;;
+	  esac
+	  ;;
+	esac
+	func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+	$opt_dry_run || if test -n "$outputname"; then
+	  ${RM}r "$tmpdir"
+	fi
+	;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      func_basename "$file"
+      name="$func_basename_result"
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+      func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+      tool_oldlib=$func_to_tool_file_result
+
+      func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+	func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+      fi
+
+      # Do each command in the postinstall commands.
+      func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+    done
+
+    test -n "$future_libdirs" && \
+      func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      $opt_dry_run && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$opt_mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+    $opt_debug
+    my_outputname="$1"
+    my_originator="$2"
+    my_pic_p="${3-no}"
+    my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+    my_dlsyms=
+
+    if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+      if test -n "$NM" && test -n "$global_symbol_pipe"; then
+	my_dlsyms="${my_outputname}S.c"
+      else
+	func_error "not configured to extract global symbols from dlpreopened files"
+      fi
+    fi
+
+    if test -n "$my_dlsyms"; then
+      case $my_dlsyms in
+      "") ;;
+      *.c)
+	# Discover the nlist of each of the dlfiles.
+	nlist="$output_objdir/${my_outputname}.nm"
+
+	func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+	# Parse the name list into a source file.
+	func_verbose "creating $output_objdir/$my_dlsyms"
+
+	$opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+	if test "$dlself" = yes; then
+	  func_verbose "generating symbol list for \`$output'"
+
+	  $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+	  # Add our own program objects to the symbol list.
+	  progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	  for progfile in $progfiles; do
+	    func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+	    func_verbose "extracting global C symbols from \`$func_to_tool_file_result'"
+	    $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+	  done
+
+	  if test -n "$exclude_expsyms"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  if test -n "$export_symbols_regex"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  # Prepare the list of exported symbols
+	  if test -z "$export_symbols"; then
+	    export_symbols="$output_objdir/$outputname.exp"
+	    $opt_dry_run || {
+	      $RM $export_symbols
+	      eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+	      case $host in
+	      *cygwin* | *mingw* | *cegcc* )
+                eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+	        ;;
+	      esac
+	    }
+	  else
+	    $opt_dry_run || {
+	      eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+	      eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	      case $host in
+	        *cygwin* | *mingw* | *cegcc* )
+	          eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+	          eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+	          ;;
+	      esac
+	    }
+	  fi
+	fi
+
+	for dlprefile in $dlprefiles; do
+	  func_verbose "extracting global C symbols from \`$dlprefile'"
+	  func_basename "$dlprefile"
+	  name="$func_basename_result"
+          case $host in
+	    *cygwin* | *mingw* | *cegcc* )
+	      # if an import library, we need to obtain dlname
+	      if func_win32_import_lib_p "$dlprefile"; then
+	        func_tr_sh "$dlprefile"
+	        eval "curr_lafile=\$libfile_$func_tr_sh_result"
+	        dlprefile_dlbasename=""
+	        if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+	          # Use subshell, to avoid clobbering current variable values
+	          dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+	          if test -n "$dlprefile_dlname" ; then
+	            func_basename "$dlprefile_dlname"
+	            dlprefile_dlbasename="$func_basename_result"
+	          else
+	            # no lafile. user explicitly requested -dlpreopen <import library>.
+	            $sharedlib_from_linklib_cmd "$dlprefile"
+	            dlprefile_dlbasename=$sharedlib_from_linklib_result
+	          fi
+	        fi
+	        $opt_dry_run || {
+	          if test -n "$dlprefile_dlbasename" ; then
+	            eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+	          else
+	            func_warning "Could not compute DLL name from $name"
+	            eval '$ECHO ": $name " >> "$nlist"'
+	          fi
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+	            $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+	        }
+	      else # not an import lib
+	        $opt_dry_run || {
+	          eval '$ECHO ": $name " >> "$nlist"'
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	        }
+	      fi
+	    ;;
+	    *)
+	      $opt_dry_run || {
+	        eval '$ECHO ": $name " >> "$nlist"'
+	        func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	        eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	      }
+	    ;;
+          esac
+	done
+
+	$opt_dry_run || {
+	  # Make sure we have at least an empty file.
+	  test -f "$nlist" || : > "$nlist"
+
+	  if test -n "$exclude_expsyms"; then
+	    $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+	    $MV "$nlist"T "$nlist"
+	  fi
+
+	  # Try sorting and uniquifying the output.
+	  if $GREP -v "^: " < "$nlist" |
+	      if sort -k 3 </dev/null >/dev/null 2>&1; then
+		sort -k 3
+	      else
+		sort +2
+	      fi |
+	      uniq > "$nlist"S; then
+	    :
+	  else
+	    $GREP -v "^: " < "$nlist" > "$nlist"S
+	  fi
+
+	  if test -f "$nlist"S; then
+	    eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+	  else
+	    echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+	  fi
+
+	  echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols.  */
+typedef struct {
+  const char *name;
+  void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+  { \"$my_originator\", (void *) 0 },"
+
+	  case $need_lib_prefix in
+	  no)
+	    eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  *)
+	    eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  esac
+	  echo >> "$output_objdir/$my_dlsyms" "\
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+	} # !$opt_dry_run
+
+	pic_flag_for_symtable=
+	case "$compile_command " in
+	*" -static "*) ;;
+	*)
+	  case $host in
+	  # compiling the symbol table file with pic_flag works around
+	  # a FreeBSD bug that causes programs to crash when -lm is
+	  # linked before any other PIC object.  But we must not use
+	  # pic_flag when linking with -static.  The problem exists in
+	  # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+	  *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+	    pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+	  *-*-hpux*)
+	    pic_flag_for_symtable=" $pic_flag"  ;;
+	  *)
+	    if test "X$my_pic_p" != Xno; then
+	      pic_flag_for_symtable=" $pic_flag"
+	    fi
+	    ;;
+	  esac
+	  ;;
+	esac
+	symtab_cflags=
+	for arg in $LTCFLAGS; do
+	  case $arg in
+	  -pie | -fpie | -fPIE) ;;
+	  *) func_append symtab_cflags " $arg" ;;
+	  esac
+	done
+
+	# Now compile the dynamic symbol file.
+	func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+	# Clean up the generated files.
+	func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+	# Transform the symbol file into the correct name.
+	symfileobj="$output_objdir/${my_outputname}S.$objext"
+	case $host in
+	*cygwin* | *mingw* | *cegcc* )
+	  if test -f "$output_objdir/$my_outputname.def"; then
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	  else
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  fi
+	  ;;
+	*)
+	  compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  ;;
+	esac
+	;;
+      *)
+	func_fatal_error "unknown suffix for \`$my_dlsyms'"
+	;;
+      esac
+    else
+      # We keep going just in case the user didn't refer to
+      # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+      # really was required.
+
+      # Nullify the symbol file.
+      compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+    fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+  $opt_debug
+  win32_libid_type="unknown"
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+      func_to_tool_file "$1" func_convert_file_msys_to_w32
+      win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+	$SED -n -e '
+	    1,100{
+		/ I /{
+		    s,.*,import,
+		    p
+		    q
+		}
+	    }'`
+      case $win32_nmres in
+      import*)  win32_libid_type="x86 archive import";;
+      *)        win32_libid_type="x86 archive static";;
+      esac
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+  $opt_debug
+  sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+  $opt_debug
+  match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+  $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+    $SED '/^Contents of section '"$match_literal"':/{
+      # Place marker at beginning of archive member dllname section
+      s/.*/====MARK====/
+      p
+      d
+    }
+    # These lines can sometimes be longer than 43 characters, but
+    # are always uninteresting
+    /:[	 ]*file format pe[i]\{,1\}-/d
+    /^In archive [^:]*:/d
+    # Ensure marker is printed
+    /^====MARK====/p
+    # Remove all lines with less than 43 characters
+    /^.\{43\}/!d
+    # From remaining lines, remove first 43 characters
+    s/^.\{43\}//' |
+    $SED -n '
+      # Join marker and all lines until next marker into a single line
+      /^====MARK====/ b para
+      H
+      $ b para
+      b
+      :para
+      x
+      s/\n//g
+      # Remove the marker
+      s/^====MARK====//
+      # Remove trailing dots and whitespace
+      s/[\. \t]*$//
+      # Print
+      /./p' |
+    # we now have a list, one entry per line, of the stringified
+    # contents of the appropriate section of all members of the
+    # archive which possess that section. Heuristic: eliminate
+    # all those which have a first or second character that is
+    # a '.' (that is, objdump's representation of an unprintable
+    # character.) This should work for all archives with less than
+    # 0x302f exports -- but will fail for DLLs whose name actually
+    # begins with a literal '.' or a single character followed by
+    # a '.'.
+    #
+    # Of those that remain, print the first one.
+    $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+  $opt_debug
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+  test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+  $opt_debug
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+  test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+  $opt_debug
+  if func_cygming_gnu_implib_p "$1" ; then
+    # binutils import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+  elif func_cygming_ms_implib_p "$1" ; then
+    # ms-generated import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+  else
+    # unknown
+    sharedlib_from_linklib_result=""
+  fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    $opt_debug
+    f_ex_an_ar_dir="$1"; shift
+    f_ex_an_ar_oldlib="$1"
+    if test "$lock_old_archive_extraction" = yes; then
+      lockfile=$f_ex_an_ar_oldlib.lock
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    fi
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+		   'stat=$?; rm -f "$lockfile"; exit $stat'
+    if test "$lock_old_archive_extraction" = yes; then
+      $opt_dry_run || rm -f "$lockfile"
+    fi
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+    fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    $opt_debug
+    my_gentop="$1"; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=""
+    my_xlib=""
+    my_xabs=""
+    my_xdir=""
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+	[\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+	*) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      func_basename "$my_xlib"
+      my_xlib="$func_basename_result"
+      my_xlib_u=$my_xlib
+      while :; do
+        case " $extracted_archives " in
+	*" $my_xlib_u "*)
+	  func_arith $extracted_serial + 1
+	  extracted_serial=$func_arith_result
+	  my_xlib_u=lt$extracted_serial-$my_xlib ;;
+	*) break ;;
+	esac
+      done
+      extracted_archives="$extracted_archives $my_xlib_u"
+      my_xdir="$my_gentop/$my_xlib_u"
+
+      func_mkdir_p "$my_xdir"
+
+      case $host in
+      *-darwin*)
+	func_verbose "Extracting $my_xabs"
+	# Do not bother doing anything if just a dry run
+	$opt_dry_run || {
+	  darwin_orig_dir=`pwd`
+	  cd $my_xdir || exit $?
+	  darwin_archive=$my_xabs
+	  darwin_curdir=`pwd`
+	  darwin_base_archive=`basename "$darwin_archive"`
+	  darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+	  if test -n "$darwin_arches"; then
+	    darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+	    darwin_arch=
+	    func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+	    for darwin_arch in  $darwin_arches ; do
+	      func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+	      cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+	      cd "$darwin_curdir"
+	      $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+	    done # $darwin_arches
+            ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+	    darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+	    darwin_file=
+	    darwin_files=
+	    for darwin_file in $darwin_filelist; do
+	      darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+	      $LIPO -create -output "$darwin_file" $darwin_files
+	    done # $darwin_filelist
+	    $RM -rf unfat-$$
+	    cd "$darwin_orig_dir"
+	  else
+	    cd $darwin_orig_dir
+	    func_extract_an_archive "$my_xdir" "$my_xabs"
+	  fi # $darwin_arches
+	} # !$opt_dry_run
+	;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+	;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+    done
+
+    func_extract_archives_result="$my_oldobjs"
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable.  Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take.  If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory.  This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+	func_emit_wrapper_arg1=${1-no}
+
+	$ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variables:
+  generated_by_libtool_version='$macro_version'
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$ECHO are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    file=\"\$0\""
+
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+    $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+    ECHO=\"$qECHO\"
+  fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+  lt_script_arg0=\$0
+  shift
+  for lt_opt
+  do
+    case \"\$lt_opt\" in
+    --lt-debug) lt_option_debug=1 ;;
+    --lt-dump-script)
+        lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+        test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+        lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+        cat \"\$lt_dump_D/\$lt_dump_F\"
+        exit 0
+      ;;
+    --lt-*)
+        \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+        exit 1
+      ;;
+    esac
+  done
+
+  # Print the debug banner immediately:
+  if test -n \"\$lt_option_debug\"; then
+    echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2
+  fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+  lt_dump_args_N=1;
+  for lt_arg
+  do
+    \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\"
+    lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+  done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+  case $host in
+  # Backslashes separate directories on plain windows
+  *-*-mingw | *-*-os2* | *-cegcc*)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+    ;;
+
+  *)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+    ;;
+  esac
+  $ECHO "\
+      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+      exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+  case \" \$* \" in
+  *\\ --lt-*)
+    for lt_wr_arg
+    do
+      case \$lt_wr_arg in
+      --lt-*) ;;
+      *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+      esac
+      shift
+    done ;;
+  esac
+  func_exec_program_core \${1+\"\$@\"}
+}
+
+  # Parse options
+  func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+  done
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+  if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+    # special case for '.'
+    if test \"\$thisdir\" = \".\"; then
+      thisdir=\`pwd\`
+    fi
+    # remove .libs from thisdir
+    case \"\$thisdir\" in
+    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+    $objdir )   thisdir=. ;;
+    esac
+  fi
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+	if test "$fast_install" = yes; then
+	  $ECHO "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" ||
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $MKDIR \"\$progdir\"
+    else
+      $RM \"\$progdir/\$file\"
+    fi"
+
+	  $ECHO "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+	$ECHO \"\$relink_command_output\" >&2
+	$RM \"\$progdir/\$file\"
+	exit 1
+      fi
+    fi
+
+    $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $RM \"\$progdir/\$program\";
+      $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $RM \"\$progdir/\$file\"
+  fi"
+	else
+	  $ECHO "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+	fi
+
+	$ECHO "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+	# fixup the dll searchpath if we need to.
+	#
+	# Fix the DLL searchpath if we need to.  Do this before prepending
+	# to shlibpath, because on Windows, both are PATH and uninstalled
+	# libraries must come first.
+	if test -n "$dllsearchpath"; then
+	  $ECHO "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+	fi
+
+	# Export our shlibpath_var if we have one.
+	if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	  $ECHO "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+	fi
+
+	$ECHO "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+      func_exec_program \${1+\"\$@\"}
+    fi
+  else
+    # The program doesn't exist.
+    \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+    \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+    \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+	cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+*/
+EOF
+	    cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+#  include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+#  define _INTPTR_T_DEFINED
+#  define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+  defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+#  define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+	(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#if defined(LT_DEBUGWRAPPER)
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+	    cat <<EOF
+volatile const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+	    if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+              func_to_host_path "$temp_rpath"
+	      cat <<EOF
+const char * LIB_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * LIB_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test -n "$dllsearchpath"; then
+              func_to_host_path "$dllsearchpath:"
+	      cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test "$fast_install" = yes; then
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+	    else
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+	    fi
+
+
+	    cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX         "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt            = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int  newargc;
+  char *tmp_pathspec;
+  char *actual_cwrapper_path;
+  char *actual_cwrapper_name;
+  char *target_name;
+  char *lt_argv_zero;
+  intptr_t rval = 127;
+
+  int i;
+
+  program_name = (char *) xstrdup (base_name (argv[0]));
+  newargz = XMALLOC (char *, argc + 1);
+
+  /* very simple arg parsing; don't want to rely on getopt
+   * also, copy all non cwrapper options to newargz, except
+   * argz[0], which is handled differently
+   */
+  newargc=0;
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], dumpscript_opt) == 0)
+	{
+EOF
+	    case "$host" in
+	      *mingw* | *cygwin* )
+		# make stdout use "unix" line endings
+		echo "          setmode(1,_O_BINARY);"
+		;;
+	      esac
+
+	    cat <<"EOF"
+	  lt_dump_script (stdout);
+	  return 0;
+	}
+      if (strcmp (argv[i], debug_opt) == 0)
+	{
+          lt_debug = 1;
+          continue;
+	}
+      if (strcmp (argv[i], ltwrapper_option_prefix) == 0)
+        {
+          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+             namespace, but it is not one of the ones we know about and
+             have already dealt with, above (inluding dump-script), then
+             report an error. Otherwise, targets might begin to believe
+             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+             namespace. The first time any user complains about this, we'll
+             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+             or a configure.ac-settable value.
+           */
+          lt_fatal (__FILE__, __LINE__,
+		    "unrecognized %s option: '%s'",
+                    ltwrapper_option_prefix, argv[i]);
+        }
+      /* otherwise ... */
+      newargz[++newargc] = xstrdup (argv[i]);
+    }
+  newargz[++newargc] = NULL;
+
+EOF
+	    cat <<EOF
+  /* The GNU banner must be the first non-error debug message */
+  lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\n");
+EOF
+	    cat <<"EOF"
+  lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+  tmp_pathspec = find_executable (argv[0]);
+  if (tmp_pathspec == NULL)
+    lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (before symlink chase) at: %s\n",
+		  tmp_pathspec);
+
+  actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (after symlink chase) at: %s\n",
+		  actual_cwrapper_path);
+  XFREE (tmp_pathspec);
+
+  actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+  strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+  /* wrapper name transforms */
+  strendzap (actual_cwrapper_name, ".exe");
+  tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+  XFREE (actual_cwrapper_name);
+  actual_cwrapper_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  /* target_name transforms -- use actual target program name; might have lt- prefix */
+  target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+  strendzap (target_name, ".exe");
+  tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+  XFREE (target_name);
+  target_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(main) libtool target name: %s\n",
+		  target_name);
+EOF
+
+	    cat <<EOF
+  newargz[0] =
+    XMALLOC (char, (strlen (actual_cwrapper_path) +
+		    strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+  strcpy (newargz[0], actual_cwrapper_path);
+  strcat (newargz[0], "$objdir");
+  strcat (newargz[0], "/");
+EOF
+
+	    cat <<"EOF"
+  /* stop here, and copy so we don't have to do this twice */
+  tmp_pathspec = xstrdup (newargz[0]);
+
+  /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+  strcat (newargz[0], actual_cwrapper_name);
+
+  /* DO want the lt- prefix here if it exists, so use target_name */
+  lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+  XFREE (tmp_pathspec);
+  tmp_pathspec = NULL;
+EOF
+
+	    case $host_os in
+	      mingw*)
+	    cat <<"EOF"
+  {
+    char* p;
+    while ((p = strchr (newargz[0], '\\')) != NULL)
+      {
+	*p = '/';
+      }
+    while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+      {
+	*p = '/';
+      }
+  }
+EOF
+	    ;;
+	    esac
+
+	    cat <<"EOF"
+  XFREE (target_name);
+  XFREE (actual_cwrapper_path);
+  XFREE (actual_cwrapper_name);
+
+  lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+  lt_setenv ("DUALCASE", "1");  /* for MSK sh */
+  /* Update the DLL searchpath.  EXE_PATH_VALUE ($dllsearchpath) must
+     be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+     because on Windows, both *_VARNAMEs are PATH but uninstalled
+     libraries must come first. */
+  lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+  lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+  lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+		  nonnull (lt_argv_zero));
+  for (i = 0; i < newargc; i++)
+    {
+      lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+		      i, nonnull (newargz[i]));
+    }
+
+EOF
+
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+  /* execv doesn't actually work on mingw as expected on unix */
+  newargz = prepare_spawn (newargz);
+  rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+  if (rval == -1)
+    {
+      /* failed to start process */
+      lt_debugprintf (__FILE__, __LINE__,
+		      "(main) failed to launch target \"%s\": %s\n",
+		      lt_argv_zero, nonnull (strerror (errno)));
+      return 127;
+    }
+  return rval;
+EOF
+		;;
+	      *)
+		cat <<"EOF"
+  execv (lt_argv_zero, newargz);
+  return rval; /* =127, but avoids unused variable warning */
+EOF
+		;;
+	    esac
+
+	    cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+  void *p = (void *) malloc (num);
+  if (!p)
+    lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+			  string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+  const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return base;
+}
+
+int
+check_executable (const char *path)
+{
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if ((stat (path, &st) >= 0)
+      && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+    return 1;
+  else
+    return 0;
+}
+
+int
+make_executable (const char *path)
+{
+  int rval = 0;
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if (stat (path, &st) >= 0)
+    {
+      rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+    }
+  return rval;
+}
+
+/* Searches for the full path of the wrapper.  Returns
+   newly allocated full path name if found, NULL otherwise
+   Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+  int has_slash = 0;
+  const char *p;
+  const char *p_next;
+  /* static buffer for getcwd */
+  char tmp[LT_PATHMAX + 1];
+  int tmp_len;
+  char *concat_name;
+
+  lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+                  nonempty (wrapper));
+
+  if ((wrapper == NULL) || (*wrapper == '\0'))
+    return NULL;
+
+  /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+    {
+      concat_name = xstrdup (wrapper);
+      if (check_executable (concat_name))
+	return concat_name;
+      XFREE (concat_name);
+    }
+  else
+    {
+#endif
+      if (IS_DIR_SEPARATOR (wrapper[0]))
+	{
+	  concat_name = xstrdup (wrapper);
+	  if (check_executable (concat_name))
+	    return concat_name;
+	  XFREE (concat_name);
+	}
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+    }
+#endif
+
+  for (p = wrapper; *p; p++)
+    if (*p == '/')
+      {
+	has_slash = 1;
+	break;
+      }
+  if (!has_slash)
+    {
+      /* no slashes; search PATH */
+      const char *path = getenv ("PATH");
+      if (path != NULL)
+	{
+	  for (p = path; *p; p = p_next)
+	    {
+	      const char *q;
+	      size_t p_len;
+	      for (q = p; *q; q++)
+		if (IS_PATH_SEPARATOR (*q))
+		  break;
+	      p_len = q - p;
+	      p_next = (*q == '\0' ? q : q + 1);
+	      if (p_len == 0)
+		{
+		  /* empty path: current directory */
+		  if (getcwd (tmp, LT_PATHMAX) == NULL)
+		    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+                              nonnull (strerror (errno)));
+		  tmp_len = strlen (tmp);
+		  concat_name =
+		    XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, tmp, tmp_len);
+		  concat_name[tmp_len] = '/';
+		  strcpy (concat_name + tmp_len + 1, wrapper);
+		}
+	      else
+		{
+		  concat_name =
+		    XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, p, p_len);
+		  concat_name[p_len] = '/';
+		  strcpy (concat_name + p_len + 1, wrapper);
+		}
+	      if (check_executable (concat_name))
+		return concat_name;
+	      XFREE (concat_name);
+	    }
+	}
+      /* not found in PATH; assume curdir */
+    }
+  /* Relative path | not found in path: prepend cwd */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+              nonnull (strerror (errno)));
+  tmp_len = strlen (tmp);
+  concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+  memcpy (concat_name, tmp, tmp_len);
+  concat_name[tmp_len] = '/';
+  strcpy (concat_name + tmp_len + 1, wrapper);
+
+  if (check_executable (concat_name))
+    return concat_name;
+  XFREE (concat_name);
+  return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+  return xstrdup (pathspec);
+#else
+  char buf[LT_PATHMAX];
+  struct stat s;
+  char *tmp_pathspec = xstrdup (pathspec);
+  char *p;
+  int has_symlinks = 0;
+  while (strlen (tmp_pathspec) && !has_symlinks)
+    {
+      lt_debugprintf (__FILE__, __LINE__,
+		      "checking path component for symlinks: %s\n",
+		      tmp_pathspec);
+      if (lstat (tmp_pathspec, &s) == 0)
+	{
+	  if (S_ISLNK (s.st_mode) != 0)
+	    {
+	      has_symlinks = 1;
+	      break;
+	    }
+
+	  /* search backwards for last DIR_SEPARATOR */
+	  p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+	  while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    p--;
+	  if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    {
+	      /* no more DIR_SEPARATORS left */
+	      break;
+	    }
+	  *p = '\0';
+	}
+      else
+	{
+	  lt_fatal (__FILE__, __LINE__,
+		    "error accessing file \"%s\": %s",
+		    tmp_pathspec, nonnull (strerror (errno)));
+	}
+    }
+  XFREE (tmp_pathspec);
+
+  if (!has_symlinks)
+    {
+      return xstrdup (pathspec);
+    }
+
+  tmp_pathspec = realpath (pathspec, buf);
+  if (tmp_pathspec == 0)
+    {
+      lt_fatal (__FILE__, __LINE__,
+		"could not follow symlinks for %s", pathspec);
+    }
+  return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert (str != NULL);
+  assert (pat != NULL);
+
+  len = strlen (str);
+  patlen = strlen (pat);
+
+  if (patlen <= len)
+    {
+      str += len - patlen;
+      if (strcmp (str, pat) == 0)
+	*str = '\0';
+    }
+  return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+  va_list args;
+  if (lt_debug)
+    {
+      (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+      va_start (args, fmt);
+      (void) vfprintf (stderr, fmt, args);
+      va_end (args);
+    }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+	       int line, const char *mode,
+	       const char *message, va_list ap)
+{
+  fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+  va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+  return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+  return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_setenv) setting '%s' to '%s'\n",
+                  nonnull (name), nonnull (value));
+  {
+#ifdef HAVE_SETENV
+    /* always make a copy, for consistency with !HAVE_SETENV */
+    char *str = xstrdup (value);
+    setenv (name, str, 1);
+#else
+    int len = strlen (name) + 1 + strlen (value) + 1;
+    char *str = XMALLOC (char, len);
+    sprintf (str, "%s=%s", name, value);
+    if (putenv (str) != EXIT_SUCCESS)
+      {
+        XFREE (str);
+      }
+#endif
+  }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+  char *new_value;
+  if (orig_value && *orig_value)
+    {
+      int orig_value_len = strlen (orig_value);
+      int add_len = strlen (add);
+      new_value = XMALLOC (char, add_len + orig_value_len + 1);
+      if (to_end)
+        {
+          strcpy (new_value, orig_value);
+          strcpy (new_value + orig_value_len, add);
+        }
+      else
+        {
+          strcpy (new_value, add);
+          strcpy (new_value + add_len, orig_value);
+        }
+    }
+  else
+    {
+      new_value = xstrdup (add);
+    }
+  return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      /* some systems can't cope with a ':'-terminated path #' */
+      int len = strlen (new_value);
+      while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+        {
+          new_value[len-1] = '\0';
+        }
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+EOF
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+   Note that spawn() does not by itself call the command interpreter
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+         GetVersionEx(&v);
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+      }) ? "cmd.exe" : "command.com").
+   Instead it simply concatenates the arguments, separated by ' ', and calls
+   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+   special way:
+   - Space and tab are interpreted as delimiters. They are not treated as
+     delimiters if they are surrounded by double quotes: "...".
+   - Unescaped double quotes are removed from the input. Their only effect is
+     that within double quotes, space and tab are treated like normal
+     characters.
+   - Backslashes not followed by double quotes are not special.
+   - But 2*n+1 backslashes followed by a double quote become
+     n backslashes followed by a double quote (n >= 0):
+       \" -> "
+       \\\" -> \"
+       \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+  size_t argc;
+  char **new_argv;
+  size_t i;
+
+  /* Count number of arguments.  */
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  /* Allocate new argument vector.  */
+  new_argv = XMALLOC (char *, argc + 1);
+
+  /* Put quoted arguments into the new argument vector.  */
+  for (i = 0; i < argc; i++)
+    {
+      const char *string = argv[i];
+
+      if (string[0] == '\0')
+	new_argv[i] = xstrdup ("\"\"");
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+	{
+	  int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+	  size_t length;
+	  unsigned int backslashes;
+	  const char *s;
+	  char *quoted_string;
+	  char *p;
+
+	  length = 0;
+	  backslashes = 0;
+	  if (quote_around)
+	    length++;
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		length += backslashes + 1;
+	      length++;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    length += backslashes + 1;
+
+	  quoted_string = XMALLOC (char, length + 1);
+
+	  p = quoted_string;
+	  backslashes = 0;
+	  if (quote_around)
+	    *p++ = '"';
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		{
+		  unsigned int j;
+		  for (j = backslashes + 1; j > 0; j--)
+		    *p++ = '\\';
+		}
+	      *p++ = c;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    {
+	      unsigned int j;
+	      for (j = backslashes; j > 0; j--)
+		*p++ = '\\';
+	      *p++ = '"';
+	    }
+	  *p = '\0';
+
+	  new_argv[i] = quoted_string;
+	}
+      else
+	new_argv[i] = (char *) string;
+    }
+  new_argv[argc] = NULL;
+
+  return new_argv;
+}
+EOF
+		;;
+	    esac
+
+            cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+	    func_emit_wrapper yes |
+	      $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/  fputs ("\1", f);/p
+g
+D'
+            cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+    $opt_debug
+    case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+    *import*) : ;;
+    *) false ;;
+    esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+    $opt_debug
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # which system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll which has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args=$nonopt
+    base_compile="$nonopt $@"
+    compile_command=$nonopt
+    finalize_command=$nonopt
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+    new_inherited_linker_flags=
+
+    avoid_version=no
+    bindir=
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=no
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+    weak_libs=
+    single_module="${wl}-single_module"
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	break
+	;;
+      -all-static | -static | -static-libtool-libs)
+	case $arg in
+	-all-static)
+	  if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+	    func_warning "complete static linking is impossible in this configuration"
+	  fi
+	  if test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	-static)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=built
+	  ;;
+	-static-libtool-libs)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	esac
+	build_libtool_libs=no
+	build_old_libs=yes
+	break
+	;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg="$1"
+      shift
+      func_quote_for_eval "$arg"
+      qarg=$func_quote_for_eval_unquoted_result
+      func_append libtool_args " $func_quote_for_eval_result"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+	case $prev in
+	output)
+	  func_append compile_command " @OUTPUT@"
+	  func_append finalize_command " @OUTPUT@"
+	  ;;
+	esac
+
+	case $prev in
+	bindir)
+	  bindir="$arg"
+	  prev=
+	  continue
+	  ;;
+	dlfiles|dlprefiles)
+	  if test "$preload" = no; then
+	    # Add the symbol object into the linking commands.
+	    func_append compile_command " @SYMFILE@"
+	    func_append finalize_command " @SYMFILE@"
+	    preload=yes
+	  fi
+	  case $arg in
+	  *.la | *.lo) ;;  # We handle these cases below.
+	  force)
+	    if test "$dlself" = no; then
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  self)
+	    if test "$prev" = dlprefiles; then
+	      dlself=yes
+	    elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+	      dlself=yes
+	    else
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  *)
+	    if test "$prev" = dlfiles; then
+	      func_append dlfiles " $arg"
+	    else
+	      func_append dlprefiles " $arg"
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  esac
+	  ;;
+	expsyms)
+	  export_symbols="$arg"
+	  test -f "$arg" \
+	    || func_fatal_error "symbol file \`$arg' does not exist"
+	  prev=
+	  continue
+	  ;;
+	expsyms_regex)
+	  export_symbols_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	framework)
+	  case $host in
+	    *-*-darwin*)
+	      case "$deplibs " in
+		*" $qarg.ltframework "*) ;;
+		*) func_append deplibs " $qarg.ltframework" # this is fixed later
+		   ;;
+	      esac
+	      ;;
+	  esac
+	  prev=
+	  continue
+	  ;;
+	inst_prefix)
+	  inst_prefix_dir="$arg"
+	  prev=
+	  continue
+	  ;;
+	objectlist)
+	  if test -f "$arg"; then
+	    save_arg=$arg
+	    moreargs=
+	    for fil in `cat "$save_arg"`
+	    do
+#	      func_append moreargs " $fil"
+	      arg=$fil
+	      # A libtool-controlled object.
+
+	      # Check to see that this really is a libtool object.
+	      if func_lalib_unsafe_p "$arg"; then
+		pic_object=
+		non_pic_object=
+
+		# Read the .lo file
+		func_source "$arg"
+
+		if test -z "$pic_object" ||
+		   test -z "$non_pic_object" ||
+		   test "$pic_object" = none &&
+		   test "$non_pic_object" = none; then
+		  func_fatal_error "cannot find name of object for \`$arg'"
+		fi
+
+		# Extract subdirectory from the argument.
+		func_dirname "$arg" "/" ""
+		xdir="$func_dirname_result"
+
+		if test "$pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  pic_object="$xdir$pic_object"
+
+		  if test "$prev" = dlfiles; then
+		    if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		      func_append dlfiles " $pic_object"
+		      prev=
+		      continue
+		    else
+		      # If libtool objects are unsupported, then we need to preload.
+		      prev=dlprefiles
+		    fi
+		  fi
+
+		  # CHECK ME:  I think I busted this.  -Ossama
+		  if test "$prev" = dlprefiles; then
+		    # Preload the old-style object.
+		    func_append dlprefiles " $pic_object"
+		    prev=
+		  fi
+
+		  # A PIC object.
+		  func_append libobjs " $pic_object"
+		  arg="$pic_object"
+		fi
+
+		# Non-PIC object.
+		if test "$non_pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  non_pic_object="$xdir$non_pic_object"
+
+		  # A standard non-PIC object
+		  func_append non_pic_objects " $non_pic_object"
+		  if test -z "$pic_object" || test "$pic_object" = none ; then
+		    arg="$non_pic_object"
+		  fi
+		else
+		  # If the PIC object exists, use it instead.
+		  # $xdir was prepended to $pic_object above.
+		  non_pic_object="$pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+		fi
+	      else
+		# Only an error if not doing a dry-run.
+		if $opt_dry_run; then
+		  # Extract subdirectory from the argument.
+		  func_dirname "$arg" "/" ""
+		  xdir="$func_dirname_result"
+
+		  func_lo2o "$arg"
+		  pic_object=$xdir$objdir/$func_lo2o_result
+		  non_pic_object=$xdir$func_lo2o_result
+		  func_append libobjs " $pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+	        else
+		  func_fatal_error "\`$arg' is not a valid libtool object"
+		fi
+	      fi
+	    done
+	  else
+	    func_fatal_error "link input file \`$arg' does not exist"
+	  fi
+	  arg=$save_arg
+	  prev=
+	  continue
+	  ;;
+	precious_regex)
+	  precious_files_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	release)
+	  release="-$arg"
+	  prev=
+	  continue
+	  ;;
+	rpath | xrpath)
+	  # We need an absolute path.
+	  case $arg in
+	  [\\/]* | [A-Za-z]:[\\/]*) ;;
+	  *)
+	    func_fatal_error "only absolute run-paths are allowed"
+	    ;;
+	  esac
+	  if test "$prev" = rpath; then
+	    case "$rpath " in
+	    *" $arg "*) ;;
+	    *) func_append rpath " $arg" ;;
+	    esac
+	  else
+	    case "$xrpath " in
+	    *" $arg "*) ;;
+	    *) func_append xrpath " $arg" ;;
+	    esac
+	  fi
+	  prev=
+	  continue
+	  ;;
+	shrext)
+	  shrext_cmds="$arg"
+	  prev=
+	  continue
+	  ;;
+	weak)
+	  func_append weak_libs " $arg"
+	  prev=
+	  continue
+	  ;;
+	xcclinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xcompiler)
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xlinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $wl$qarg"
+	  prev=
+	  func_append compile_command " $wl$qarg"
+	  func_append finalize_command " $wl$qarg"
+	  continue
+	  ;;
+	*)
+	  eval "$prev=\"\$arg\""
+	  prev=
+	  continue
+	  ;;
+	esac
+      fi # test -n "$prev"
+
+      prevarg="$arg"
+
+      case $arg in
+      -all-static)
+	if test -n "$link_static_flag"; then
+	  # See comment for -static flag below, for more details.
+	  func_append compile_command " $link_static_flag"
+	  func_append finalize_command " $link_static_flag"
+	fi
+	continue
+	;;
+
+      -allow-undefined)
+	# FIXME: remove this flag sometime in the future.
+	func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+	;;
+
+      -avoid-version)
+	avoid_version=yes
+	continue
+	;;
+
+      -bindir)
+	prev=bindir
+	continue
+	;;
+
+      -dlopen)
+	prev=dlfiles
+	continue
+	;;
+
+      -dlpreopen)
+	prev=dlprefiles
+	continue
+	;;
+
+      -export-dynamic)
+	export_dynamic=yes
+	continue
+	;;
+
+      -export-symbols | -export-symbols-regex)
+	if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	  func_fatal_error "more than one -exported-symbols argument is not allowed"
+	fi
+	if test "X$arg" = "X-export-symbols"; then
+	  prev=expsyms
+	else
+	  prev=expsyms_regex
+	fi
+	continue
+	;;
+
+      -framework)
+	prev=framework
+	continue
+	;;
+
+      -inst-prefix-dir)
+	prev=inst_prefix
+	continue
+	;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+	case $with_gcc/$host in
+	no/*-*-irix* | /*-*-irix*)
+	  func_append compile_command " $arg"
+	  func_append finalize_command " $arg"
+	  ;;
+	esac
+	continue
+	;;
+
+      -L*)
+	func_stripname "-L" '' "$arg"
+	if test -z "$func_stripname_result"; then
+	  if test "$#" -gt 0; then
+	    func_fatal_error "require no space between \`-L' and \`$1'"
+	  else
+	    func_fatal_error "need path for \`-L' option"
+	  fi
+	fi
+	func_resolve_sysroot "$func_stripname_result"
+	dir=$func_resolve_sysroot_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  absdir=`cd "$dir" && pwd`
+	  test -z "$absdir" && \
+	    func_fatal_error "cannot determine absolute directory name of \`$dir'"
+	  dir="$absdir"
+	  ;;
+	esac
+	case "$deplibs " in
+	*" -L$dir "* | *" $arg "*)
+	  # Will only happen for absolute or sysroot arguments
+	  ;;
+	*)
+	  # Preserve sysroot, but never include relative directories
+	  case $dir in
+	    [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+	    *) func_append deplibs " -L$dir" ;;
+	  esac
+	  func_append lib_search_path " $dir"
+	  ;;
+	esac
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$dir:"*) ;;
+	  ::) dllsearchpath=$dir;;
+	  *) func_append dllsearchpath ":$dir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+	continue
+	;;
+
+      -l*)
+	if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # These systems don't actually have a C or math library (as such)
+	    continue
+	    ;;
+	  *-*-os2*)
+	    # These systems don't actually have a C library (as such)
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C and math libraries are in the System framework
+	    func_append deplibs " System.ltframework"
+	    continue
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  esac
+	elif test "X$arg" = "X-lc_r"; then
+	 case $host in
+	 *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	   # Do not include libc_r directly, use -pthread flag.
+	   continue
+	   ;;
+	 esac
+	fi
+	func_append deplibs " $arg"
+	continue
+	;;
+
+      -module)
+	module=yes
+	continue
+	;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      # Darwin uses the -arch flag to determine output architecture.
+      -model|-arch|-isysroot|--sysroot)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	prev=xcompiler
+	continue
+	;;
+
+      -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+      |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	case "$new_inherited_linker_flags " in
+	    *" $arg "*) ;;
+	    * ) func_append new_inherited_linker_flags " $arg" ;;
+	esac
+	continue
+	;;
+
+      -multi_module)
+	single_module="${wl}-multi_module"
+	continue
+	;;
+
+      -no-fast-install)
+	fast_install=no
+	continue
+	;;
+
+      -no-install)
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+	  # The PATH hackery in wrapper scripts is required on Windows
+	  # and Darwin in order for the loader to find any dlls it needs.
+	  func_warning "\`-no-install' is ignored for $host"
+	  func_warning "assuming \`-no-fast-install' instead"
+	  fast_install=no
+	  ;;
+	*) no_install=yes ;;
+	esac
+	continue
+	;;
+
+      -no-undefined)
+	allow_undefined=no
+	continue
+	;;
+
+      -objectlist)
+	prev=objectlist
+	continue
+	;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+	prev=precious_regex
+	continue
+	;;
+
+      -release)
+	prev=release
+	continue
+	;;
+
+      -rpath)
+	prev=rpath
+	continue
+	;;
+
+      -R)
+	prev=xrpath
+	continue
+	;;
+
+      -R*)
+	func_stripname '-R' '' "$arg"
+	dir=$func_stripname_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	=*)
+	  func_stripname '=' '' "$dir"
+	  dir=$lt_sysroot$func_stripname_result
+	  ;;
+	*)
+	  func_fatal_error "only absolute run-paths are allowed"
+	  ;;
+	esac
+	case "$xrpath " in
+	*" $dir "*) ;;
+	*) func_append xrpath " $dir" ;;
+	esac
+	continue
+	;;
+
+      -shared)
+	# The effects of -shared are defined in a previous loop.
+	continue
+	;;
+
+      -shrext)
+	prev=shrext
+	continue
+	;;
+
+      -static | -static-libtool-libs)
+	# The effects of -static are defined in a previous loop.
+	# We used to do the same as -all-static on platforms that
+	# didn't have a PIC flag, but the assumption that the effects
+	# would be equivalent was wrong.  It would break on at least
+	# Digital Unix and AIX.
+	continue
+	;;
+
+      -thread-safe)
+	thread_safe=yes
+	continue
+	;;
+
+      -version-info)
+	prev=vinfo
+	continue
+	;;
+
+      -version-number)
+	prev=vinfo
+	vinfo_number=yes
+	continue
+	;;
+
+      -weak)
+        prev=weak
+	continue
+	;;
+
+      -Wc,*)
+	func_stripname '-Wc,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  func_append arg " $func_quote_for_eval_result"
+	  func_append compiler_flags " $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Wl,*)
+	func_stripname '-Wl,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  func_append arg " $wl$func_quote_for_eval_result"
+	  func_append compiler_flags " $wl$func_quote_for_eval_result"
+	  func_append linker_flags " $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Xcompiler)
+	prev=xcompiler
+	continue
+	;;
+
+      -Xlinker)
+	prev=xlinker
+	continue
+	;;
+
+      -XCClinker)
+	prev=xcclinker
+	continue
+	;;
+
+      # -msg_* for osf cc
+      -msg_*)
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      # Flags to be passed through unchanged, with rationale:
+      # -64, -mips[0-9]      enable 64-bit mode for the SGI compiler
+      # -r[0-9][0-9]*        specify processor for the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+      # +DA*, +DD*           enable 64-bit mode for the HP compiler
+      # -q*                  compiler args for the IBM compiler
+      # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+      # -F/path              path to uninstalled frameworks, gcc on darwin
+      # -p, -pg, --coverage, -fprofile-*  profiling flags for GCC
+      # @file                GCC response files
+      # -tp=*                Portland pgcc target processor selection
+      # --sysroot=*          for sysroot support
+      # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+      -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+        func_append compile_command " $arg"
+        func_append finalize_command " $arg"
+        func_append compiler_flags " $arg"
+        continue
+        ;;
+
+      # Some other compiler flag.
+      -* | +*)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      *.$objext)
+	# A standard object.
+	func_append objs " $arg"
+	;;
+
+      *.lo)
+	# A libtool-controlled object.
+
+	# Check to see that this really is a libtool object.
+	if func_lalib_unsafe_p "$arg"; then
+	  pic_object=
+	  non_pic_object=
+
+	  # Read the .lo file
+	  func_source "$arg"
+
+	  if test -z "$pic_object" ||
+	     test -z "$non_pic_object" ||
+	     test "$pic_object" = none &&
+	     test "$non_pic_object" = none; then
+	    func_fatal_error "cannot find name of object for \`$arg'"
+	  fi
+
+	  # Extract subdirectory from the argument.
+	  func_dirname "$arg" "/" ""
+	  xdir="$func_dirname_result"
+
+	  if test "$pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    pic_object="$xdir$pic_object"
+
+	    if test "$prev" = dlfiles; then
+	      if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		func_append dlfiles " $pic_object"
+		prev=
+		continue
+	      else
+		# If libtool objects are unsupported, then we need to preload.
+		prev=dlprefiles
+	      fi
+	    fi
+
+	    # CHECK ME:  I think I busted this.  -Ossama
+	    if test "$prev" = dlprefiles; then
+	      # Preload the old-style object.
+	      func_append dlprefiles " $pic_object"
+	      prev=
+	    fi
+
+	    # A PIC object.
+	    func_append libobjs " $pic_object"
+	    arg="$pic_object"
+	  fi
+
+	  # Non-PIC object.
+	  if test "$non_pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    non_pic_object="$xdir$non_pic_object"
+
+	    # A standard non-PIC object
+	    func_append non_pic_objects " $non_pic_object"
+	    if test -z "$pic_object" || test "$pic_object" = none ; then
+	      arg="$non_pic_object"
+	    fi
+	  else
+	    # If the PIC object exists, use it instead.
+	    # $xdir was prepended to $pic_object above.
+	    non_pic_object="$pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  fi
+	else
+	  # Only an error if not doing a dry-run.
+	  if $opt_dry_run; then
+	    # Extract subdirectory from the argument.
+	    func_dirname "$arg" "/" ""
+	    xdir="$func_dirname_result"
+
+	    func_lo2o "$arg"
+	    pic_object=$xdir$objdir/$func_lo2o_result
+	    non_pic_object=$xdir$func_lo2o_result
+	    func_append libobjs " $pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  else
+	    func_fatal_error "\`$arg' is not a valid libtool object"
+	  fi
+	fi
+	;;
+
+      *.$libext)
+	# An archive.
+	func_append deplibs " $arg"
+	func_append old_deplibs " $arg"
+	continue
+	;;
+
+      *.la)
+	# A libtool-controlled library.
+
+	func_resolve_sysroot "$arg"
+	if test "$prev" = dlfiles; then
+	  # This library was specified with -dlopen.
+	  func_append dlfiles " $func_resolve_sysroot_result"
+	  prev=
+	elif test "$prev" = dlprefiles; then
+	  # The library was specified with -dlpreopen.
+	  func_append dlprefiles " $func_resolve_sysroot_result"
+	  prev=
+	else
+	  func_append deplibs " $func_resolve_sysroot_result"
+	fi
+	continue
+	;;
+
+      # Some other compiler argument.
+      *)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+      fi
+    done # argument parsing loop
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prevarg' option requires an argument"
+
+    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      func_append compile_command " $arg"
+      func_append finalize_command " $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    func_basename "$output"
+    outputname="$func_basename_result"
+    libobjs_save="$libobjs"
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    func_dirname "$output" "/" ""
+    output_objdir="$func_dirname_result$objdir"
+    func_to_tool_file "$output_objdir/"
+    tool_output_objdir=$func_to_tool_file_result
+    # Create the object directory.
+    func_mkdir_p "$output_objdir"
+
+    # Determine the type of output
+    case $output in
+    "")
+      func_fatal_help "you must specify an output file"
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if $opt_preserve_dup_deps ; then
+	case "$libs " in
+	*" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	esac
+      fi
+      func_append libs " $deplib"
+    done
+
+    if test "$linkmode" = lib; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if $opt_duplicate_compiler_generated_deps; then
+	for pre_post_dep in $predeps $postdeps; do
+	  case "$pre_post_deps " in
+	  *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+	  esac
+	  func_append pre_post_deps " $pre_post_dep"
+	done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+
+    case $linkmode in
+    lib)
+	passes="conv dlpreopen link"
+	for file in $dlfiles $dlprefiles; do
+	  case $file in
+	  *.la) ;;
+	  *)
+	    func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+	    ;;
+	  esac
+	done
+	;;
+    prog)
+	compile_deplibs=
+	finalize_deplibs=
+	alldeplibs=no
+	newdlfiles=
+	newdlprefiles=
+	passes="conv scan dlopen dlpreopen link"
+	;;
+    *)  passes="conv"
+	;;
+    esac
+
+    for pass in $passes; do
+      # The preopen pass in lib mode reverses $deplibs; put it back here
+      # so that -L comes before libs that need it for instance...
+      if test "$linkmode,$pass" = "lib,link"; then
+	## FIXME: Find the place where the list is rebuilt in the wrong
+	##        order, and fix it there properly
+        tmp_deplibs=
+	for deplib in $deplibs; do
+	  tmp_deplibs="$deplib $tmp_deplibs"
+	done
+	deplibs="$tmp_deplibs"
+      fi
+
+      if test "$linkmode,$pass" = "lib,link" ||
+	 test "$linkmode,$pass" = "prog,scan"; then
+	libs="$deplibs"
+	deplibs=
+      fi
+      if test "$linkmode" = prog; then
+	case $pass in
+	dlopen) libs="$dlfiles" ;;
+	dlpreopen) libs="$dlprefiles" ;;
+	link)
+	  libs="$deplibs %DEPLIBS%"
+	  test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
+	  ;;
+	esac
+      fi
+      if test "$linkmode,$pass" = "lib,dlpreopen"; then
+	# Collect and forward deplibs of preopened libtool libs
+	for lib in $dlprefiles; do
+	  # Ignore non-libtool-libs
+	  dependency_libs=
+	  func_resolve_sysroot "$lib"
+	  case $lib in
+	  *.la)	func_source "$func_resolve_sysroot_result" ;;
+	  esac
+
+	  # Collect preopened libtool deplibs, except any this library
+	  # has declared as weak libs
+	  for deplib in $dependency_libs; do
+	    func_basename "$deplib"
+            deplib_base=$func_basename_result
+	    case " $weak_libs " in
+	    *" $deplib_base "*) ;;
+	    *) func_append deplibs " $deplib" ;;
+	    esac
+	  done
+	done
+	libs="$dlprefiles"
+      fi
+      if test "$pass" = dlopen; then
+	# Collect dlpreopened libraries
+	save_deplibs="$deplibs"
+	deplibs=
+      fi
+
+      for deplib in $libs; do
+	lib=
+	found=no
+	case $deplib in
+	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+        |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    func_append compiler_flags " $deplib"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-l*)
+	  if test "$linkmode" != lib && test "$linkmode" != prog; then
+	    func_warning "\`-l' is ignored for archives/objects"
+	    continue
+	  fi
+	  func_stripname '-l' '' "$deplib"
+	  name=$func_stripname_result
+	  if test "$linkmode" = lib; then
+	    searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+	  else
+	    searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+	  fi
+	  for searchdir in $searchdirs; do
+	    for search_ext in .la $std_shrext .so .a; do
+	      # Search the libtool library
+	      lib="$searchdir/lib${name}${search_ext}"
+	      if test -f "$lib"; then
+		if test "$search_ext" = ".la"; then
+		  found=yes
+		else
+		  found=no
+		fi
+		break 2
+	      fi
+	    done
+	  done
+	  if test "$found" != yes; then
+	    # deplib doesn't seem to be a libtool library
+	    if test "$linkmode,$pass" = "prog,link"; then
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      deplibs="$deplib $deplibs"
+	      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    continue
+	  else # deplib is a libtool library
+	    # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+	    # We need to do some special things here, and not later.
+	    if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	      case " $predeps $postdeps " in
+	      *" $deplib "*)
+		if func_lalib_p "$lib"; then
+		  library_names=
+		  old_library=
+		  func_source "$lib"
+		  for l in $old_library $library_names; do
+		    ll="$l"
+		  done
+		  if test "X$ll" = "X$old_library" ; then # only static version available
+		    found=no
+		    func_dirname "$lib" "" "."
+		    ladir="$func_dirname_result"
+		    lib=$ladir/$old_library
+		    if test "$linkmode,$pass" = "prog,link"; then
+		      compile_deplibs="$deplib $compile_deplibs"
+		      finalize_deplibs="$deplib $finalize_deplibs"
+		    else
+		      deplibs="$deplib $deplibs"
+		      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+		    fi
+		    continue
+		  fi
+		fi
+		;;
+	      *) ;;
+	      esac
+	    fi
+	  fi
+	  ;; # -l
+	*.ltframework)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    deplibs="$deplib $deplibs"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-L*)
+	  case $linkmode in
+	  lib)
+	    deplibs="$deplib $deplibs"
+	    test "$pass" = conv && continue
+	    newdependency_libs="$deplib $newdependency_libs"
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  prog)
+	    if test "$pass" = conv; then
+	      deplibs="$deplib $deplibs"
+	      continue
+	    fi
+	    if test "$pass" = scan; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  *)
+	    func_warning "\`-L' is ignored for archives/objects"
+	    ;;
+	  esac # linkmode
+	  continue
+	  ;; # -L
+	-R*)
+	  if test "$pass" = link; then
+	    func_stripname '-R' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    dir=$func_resolve_sysroot_result
+	    # Make sure the xrpath contains only unique directories.
+	    case "$xrpath " in
+	    *" $dir "*) ;;
+	    *) func_append xrpath " $dir" ;;
+	    esac
+	  fi
+	  deplibs="$deplib $deplibs"
+	  continue
+	  ;;
+	*.la)
+	  func_resolve_sysroot "$deplib"
+	  lib=$func_resolve_sysroot_result
+	  ;;
+	*.$libext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	    continue
+	  fi
+	  case $linkmode in
+	  lib)
+	    # Linking convenience modules into shared libraries is allowed,
+	    # but linking other static libraries is non-portable.
+	    case " $dlpreconveniencelibs " in
+	    *" $deplib "*) ;;
+	    *)
+	      valid_a_lib=no
+	      case $deplibs_check_method in
+		match_pattern*)
+		  set dummy $deplibs_check_method; shift
+		  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+		  if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+		    | $EGREP "$match_pattern_regex" > /dev/null; then
+		    valid_a_lib=yes
+		  fi
+		;;
+		pass_all)
+		  valid_a_lib=yes
+		;;
+	      esac
+	      if test "$valid_a_lib" != yes; then
+		echo
+		$ECHO "*** Warning: Trying to link with static lib archive $deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because the file extensions .$libext of this argument makes me believe"
+		echo "*** that it is just a static archive that I should not use here."
+	      else
+		echo
+		$ECHO "*** Warning: Linking the shared library $output against the"
+		$ECHO "*** static library $deplib is not portable!"
+		deplibs="$deplib $deplibs"
+	      fi
+	      ;;
+	    esac
+	    continue
+	    ;;
+	  prog)
+	    if test "$pass" != link; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    continue
+	    ;;
+	  esac # linkmode
+	  ;; # *.$libext
+	*.lo | *.$objext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	  elif test "$linkmode" = prog; then
+	    if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+	      # If there is no dlopen support or we're linking statically,
+	      # we need to preload.
+	      func_append newdlprefiles " $deplib"
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      func_append newdlfiles " $deplib"
+	    fi
+	  fi
+	  continue
+	  ;;
+	%DEPLIBS%)
+	  alldeplibs=yes
+	  continue
+	  ;;
+	esac # case $deplib
+
+	if test "$found" = yes || test -f "$lib"; then :
+	else
+	  func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+	fi
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$lib" \
+	  || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+	func_dirname "$lib" "" "."
+	ladir="$func_dirname_result"
+
+	dlname=
+	dlopen=
+	dlpreopen=
+	libdir=
+	library_names=
+	old_library=
+	inherited_linker_flags=
+	# If the library was installed with an old release of libtool,
+	# it will not redefine variables installed, or shouldnotlink
+	installed=yes
+	shouldnotlink=no
+	avoidtemprpath=
+
+
+	# Read the .la file
+	func_source "$lib"
+
+	# Convert "-framework foo" to "foo.ltframework"
+	if test -n "$inherited_linker_flags"; then
+	  tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+	  for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+	    case " $new_inherited_linker_flags " in
+	      *" $tmp_inherited_linker_flag "*) ;;
+	      *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+	    esac
+	  done
+	fi
+	dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	if test "$linkmode,$pass" = "lib,link" ||
+	   test "$linkmode,$pass" = "prog,scan" ||
+	   { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+	  test -n "$dlopen" && func_append dlfiles " $dlopen"
+	  test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+	fi
+
+	if test "$pass" = conv; then
+	  # Only check for convenience libraries
+	  deplibs="$lib $deplibs"
+	  if test -z "$libdir"; then
+	    if test -z "$old_library"; then
+	      func_fatal_error "cannot find name of link library for \`$lib'"
+	    fi
+	    # It is a libtool convenience library, so add in its objects.
+	    func_append convenience " $ladir/$objdir/$old_library"
+	    func_append old_convenience " $ladir/$objdir/$old_library"
+	    tmp_libs=
+	    for deplib in $dependency_libs; do
+	      deplibs="$deplib $deplibs"
+	      if $opt_preserve_dup_deps ; then
+		case "$tmp_libs " in
+		*" $deplib "*) func_append specialdeplibs " $deplib" ;;
+		esac
+	      fi
+	      func_append tmp_libs " $deplib"
+	    done
+	  elif test "$linkmode" != prog && test "$linkmode" != lib; then
+	    func_fatal_error "\`$lib' is not a convenience library"
+	  fi
+	  continue
+	fi # $pass = conv
+
+
+	# Get the name of the library we link against.
+	linklib=
+	if test -n "$old_library" &&
+	   { test "$prefer_static_libs" = yes ||
+	     test "$prefer_static_libs,$installed" = "built,no"; }; then
+	  linklib=$old_library
+	else
+	  for l in $old_library $library_names; do
+	    linklib="$l"
+	  done
+	fi
+	if test -z "$linklib"; then
+	  func_fatal_error "cannot find name of link library for \`$lib'"
+	fi
+
+	# This library was specified with -dlopen.
+	if test "$pass" = dlopen; then
+	  if test -z "$libdir"; then
+	    func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+	  fi
+	  if test -z "$dlname" ||
+	     test "$dlopen_support" != yes ||
+	     test "$build_libtool_libs" = no; then
+	    # If there is no dlname, no dlopen support or we're linking
+	    # statically, we need to preload.  We also need to preload any
+	    # dependent libraries so libltdl's deplib preloader doesn't
+	    # bomb out in the load deplibs phase.
+	    func_append dlprefiles " $lib $dependency_libs"
+	  else
+	    func_append newdlfiles " $lib"
+	  fi
+	  continue
+	fi # $pass = dlopen
+
+	# We need an absolute path.
+	case $ladir in
+	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+	*)
+	  abs_ladir=`cd "$ladir" && pwd`
+	  if test -z "$abs_ladir"; then
+	    func_warning "cannot determine absolute directory name of \`$ladir'"
+	    func_warning "passing it literally to the linker, although it might fail"
+	    abs_ladir="$ladir"
+	  fi
+	  ;;
+	esac
+	func_basename "$lib"
+	laname="$func_basename_result"
+
+	# Find the relevant object directory and library name.
+	if test "X$installed" = Xyes; then
+	  if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    func_warning "library \`$lib' was moved."
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    libdir="$abs_ladir"
+	  else
+	    dir="$lt_sysroot$libdir"
+	    absdir="$lt_sysroot$libdir"
+	  fi
+	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+	else
+	  if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  else
+	    dir="$ladir/$objdir"
+	    absdir="$abs_ladir/$objdir"
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  fi
+	fi # $installed = yes
+	func_stripname 'lib' '.la' "$laname"
+	name=$func_stripname_result
+
+	# This library was specified with -dlpreopen.
+	if test "$pass" = dlpreopen; then
+	  if test -z "$libdir" && test "$linkmode" = prog; then
+	    func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+	  fi
+	  case "$host" in
+	    # special handling for platforms with PE-DLLs.
+	    *cygwin* | *mingw* | *cegcc* )
+	      # Linker will automatically link against shared library if both
+	      # static and shared are present.  Therefore, ensure we extract
+	      # symbols from the import library if a shared library is present
+	      # (otherwise, the dlopen module name will be incorrect).  We do
+	      # this by putting the import library name into $newdlprefiles.
+	      # We recover the dlopen module name by 'saving' the la file
+	      # name in a special purpose variable, and (later) extracting the
+	      # dlname from the la file.
+	      if test -n "$dlname"; then
+	        func_tr_sh "$dir/$linklib"
+	        eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+	        func_append newdlprefiles " $dir/$linklib"
+	      else
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      fi
+	    ;;
+	    * )
+	      # Prefer using a static library (so that no silly _DYNAMIC symbols
+	      # are required to link).
+	      if test -n "$old_library"; then
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      # Otherwise, use the dlname, so that lt_dlopen finds it.
+	      elif test -n "$dlname"; then
+	        func_append newdlprefiles " $dir/$dlname"
+	      else
+	        func_append newdlprefiles " $dir/$linklib"
+	      fi
+	    ;;
+	  esac
+	fi # $pass = dlpreopen
+
+	if test -z "$libdir"; then
+	  # Link the convenience library
+	  if test "$linkmode" = lib; then
+	    deplibs="$dir/$old_library $deplibs"
+	  elif test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$dir/$old_library $compile_deplibs"
+	    finalize_deplibs="$dir/$old_library $finalize_deplibs"
+	  else
+	    deplibs="$lib $deplibs" # used for prog,scan pass
+	  fi
+	  continue
+	fi
+
+
+	if test "$linkmode" = prog && test "$pass" != link; then
+	  func_append newlib_search_path " $ladir"
+	  deplibs="$lib $deplibs"
+
+	  linkalldeplibs=no
+	  if test "$link_all_deplibs" != no || test -z "$library_names" ||
+	     test "$build_libtool_libs" = no; then
+	    linkalldeplibs=yes
+	  fi
+
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    case $deplib in
+	    -L*) func_stripname '-L' '' "$deplib"
+	         func_resolve_sysroot "$func_stripname_result"
+	         func_append newlib_search_path " $func_resolve_sysroot_result"
+		 ;;
+	    esac
+	    # Need to link against all dependency_libs?
+	    if test "$linkalldeplibs" = yes; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      # Need to hardcode shared library paths
+	      # or/and link against static libraries
+	      newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    if $opt_preserve_dup_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $deplib"
+	  done # for deplib
+	  continue
+	fi # $linkmode = prog...
+
+	if test "$linkmode,$pass" = "prog,link"; then
+	  if test -n "$library_names" &&
+	     { { test "$prefer_static_libs" = no ||
+	         test "$prefer_static_libs,$installed" = "built,yes"; } ||
+	       test -z "$old_library"; }; then
+	    # We need to hardcode the library path
+	    if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+	      # Make sure the rpath contains only unique directories.
+	      case "$temp_rpath:" in
+	      *"$absdir:"*) ;;
+	      *) func_append temp_rpath "$absdir:" ;;
+	      esac
+	    fi
+
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi # $linkmode,$pass = prog,link...
+
+	  if test "$alldeplibs" = yes &&
+	     { test "$deplibs_check_method" = pass_all ||
+	       { test "$build_libtool_libs" = yes &&
+		 test -n "$library_names"; }; }; then
+	    # We only need to search for static libraries
+	    continue
+	  fi
+	fi
+
+	link_static=no # Whether the deplib will be linked statically
+	use_static_libs=$prefer_static_libs
+	if test "$use_static_libs" = built && test "$installed" = yes; then
+	  use_static_libs=no
+	fi
+	if test -n "$library_names" &&
+	   { test "$use_static_libs" = no || test -z "$old_library"; }; then
+	  case $host in
+	  *cygwin* | *mingw* | *cegcc*)
+	      # No point in relinking DLLs because paths are not encoded
+	      func_append notinst_deplibs " $lib"
+	      need_relink=no
+	    ;;
+	  *)
+	    if test "$installed" = no; then
+	      func_append notinst_deplibs " $lib"
+	      need_relink=yes
+	    fi
+	    ;;
+	  esac
+	  # This is a shared library
+
+	  # Warn about portability, can't link against -module's on some
+	  # systems (darwin).  Don't bleat about dlopened modules though!
+	  dlopenmodule=""
+	  for dlpremoduletest in $dlprefiles; do
+	    if test "X$dlpremoduletest" = "X$lib"; then
+	      dlopenmodule="$dlpremoduletest"
+	      break
+	    fi
+	  done
+	  if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+	    echo
+	    if test "$linkmode" = prog; then
+	      $ECHO "*** Warning: Linking the executable $output against the loadable module"
+	    else
+	      $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+	    fi
+	    $ECHO "*** $linklib is not portable!"
+	  fi
+	  if test "$linkmode" = lib &&
+	     test "$hardcode_into_libs" = yes; then
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi
+
+	  if test -n "$old_archive_from_expsyms_cmds"; then
+	    # figure out the soname
+	    set dummy $library_names
+	    shift
+	    realname="$1"
+	    shift
+	    libname=`eval "\\$ECHO \"$libname_spec\""`
+	    # use dlname if we got it. it's perfectly good, no?
+	    if test -n "$dlname"; then
+	      soname="$dlname"
+	    elif test -n "$soname_spec"; then
+	      # bleh windows
+	      case $host in
+	      *cygwin* | mingw* | *cegcc*)
+	        func_arith $current - $age
+		major=$func_arith_result
+		versuffix="-$major"
+		;;
+	      esac
+	      eval soname=\"$soname_spec\"
+	    else
+	      soname="$realname"
+	    fi
+
+	    # Make a new name for the extract_expsyms_cmds to use
+	    soroot="$soname"
+	    func_basename "$soroot"
+	    soname="$func_basename_result"
+	    func_stripname 'lib' '.dll' "$soname"
+	    newlib=libimp-$func_stripname_result.a
+
+	    # If the library has no export list, then create one now
+	    if test -f "$output_objdir/$soname-def"; then :
+	    else
+	      func_verbose "extracting exported symbol list from \`$soname'"
+	      func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+	    fi
+
+	    # Create $newlib
+	    if test -f "$output_objdir/$newlib"; then :; else
+	      func_verbose "generating import library for \`$soname'"
+	      func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+	    fi
+	    # make sure the library variables are pointing to the new library
+	    dir=$output_objdir
+	    linklib=$newlib
+	  fi # test -n "$old_archive_from_expsyms_cmds"
+
+	  if test "$linkmode" = prog || test "$opt_mode" != relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    lib_linked=yes
+	    case $hardcode_action in
+	    immediate | unsupported)
+	      if test "$hardcode_direct" = no; then
+		add="$dir/$linklib"
+		case $host in
+		  *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+		  *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+		  *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+		    *-*-unixware7*) add_dir="-L$dir" ;;
+		  *-*-darwin* )
+		    # if the lib is a (non-dlopened) module then we can not
+		    # link against it, someone is ignoring the earlier warnings
+		    if /usr/bin/file -L $add 2> /dev/null |
+			 $GREP ": [^:]* bundle" >/dev/null ; then
+		      if test "X$dlopenmodule" != "X$lib"; then
+			$ECHO "*** Warning: lib $linklib is a module, not a shared library"
+			if test -z "$old_library" ; then
+			  echo
+			  echo "*** And there doesn't seem to be a static archive available"
+			  echo "*** The link will probably fail, sorry"
+			else
+			  add="$dir/$old_library"
+			fi
+		      elif test -n "$old_library"; then
+			add="$dir/$old_library"
+		      fi
+		    fi
+		esac
+	      elif test "$hardcode_minus_L" = no; then
+		case $host in
+		*-*-sunos*) add_shlibpath="$dir" ;;
+		esac
+		add_dir="-L$dir"
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = no; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    relink)
+	      if test "$hardcode_direct" = yes &&
+	         test "$hardcode_direct_absolute" = no; then
+		add="$dir/$linklib"
+	      elif test "$hardcode_minus_L" = yes; then
+		add_dir="-L$absdir"
+		# Try looking first in the location we're being installed to.
+		if test -n "$inst_prefix_dir"; then
+		  case $libdir in
+		    [\\/]*)
+		      func_append add_dir " -L$inst_prefix_dir$libdir"
+		      ;;
+		  esac
+		fi
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = yes; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    *) lib_linked=no ;;
+	    esac
+
+	    if test "$lib_linked" != yes; then
+	      func_fatal_configuration "unsupported hardcode properties"
+	    fi
+
+	    if test -n "$add_shlibpath"; then
+	      case :$compile_shlibpath: in
+	      *":$add_shlibpath:"*) ;;
+	      *) func_append compile_shlibpath "$add_shlibpath:" ;;
+	      esac
+	    fi
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+	      test -n "$add" && compile_deplibs="$add $compile_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	      if test "$hardcode_direct" != yes &&
+		 test "$hardcode_minus_L" != yes &&
+		 test "$hardcode_shlibpath_var" = yes; then
+		case :$finalize_shlibpath: in
+		*":$libdir:"*) ;;
+		*) func_append finalize_shlibpath "$libdir:" ;;
+		esac
+	      fi
+	    fi
+	  fi
+
+	  if test "$linkmode" = prog || test "$opt_mode" = relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    # Finalize command for both is simple: just hardcode it.
+	    if test "$hardcode_direct" = yes &&
+	       test "$hardcode_direct_absolute" = no; then
+	      add="$libdir/$linklib"
+	    elif test "$hardcode_minus_L" = yes; then
+	      add_dir="-L$libdir"
+	      add="-l$name"
+	    elif test "$hardcode_shlibpath_var" = yes; then
+	      case :$finalize_shlibpath: in
+	      *":$libdir:"*) ;;
+	      *) func_append finalize_shlibpath "$libdir:" ;;
+	      esac
+	      add="-l$name"
+	    elif test "$hardcode_automatic" = yes; then
+	      if test -n "$inst_prefix_dir" &&
+		 test -f "$inst_prefix_dir$libdir/$linklib" ; then
+		add="$inst_prefix_dir$libdir/$linklib"
+	      else
+		add="$libdir/$linklib"
+	      fi
+	    else
+	      # We cannot seem to hardcode it, guess we'll fake it.
+	      add_dir="-L$libdir"
+	      # Try looking first in the location we're being installed to.
+	      if test -n "$inst_prefix_dir"; then
+		case $libdir in
+		  [\\/]*)
+		    func_append add_dir " -L$inst_prefix_dir$libdir"
+		    ;;
+		esac
+	      fi
+	      add="-l$name"
+	    fi
+
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+	      test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	    fi
+	  fi
+	elif test "$linkmode" = prog; then
+	  # Here we assume that one of hardcode_direct or hardcode_minus_L
+	  # is not unsupported.  This is valid on all known static and
+	  # shared platforms.
+	  if test "$hardcode_direct" != unsupported; then
+	    test -n "$old_library" && linklib="$old_library"
+	    compile_deplibs="$dir/$linklib $compile_deplibs"
+	    finalize_deplibs="$dir/$linklib $finalize_deplibs"
+	  else
+	    compile_deplibs="-l$name -L$dir $compile_deplibs"
+	    finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+	  fi
+	elif test "$build_libtool_libs" = yes; then
+	  # Not a shared library
+	  if test "$deplibs_check_method" != pass_all; then
+	    # We're trying link a shared library against a static one
+	    # but the system doesn't support it.
+
+	    # Just print a warning and add the library to dependency_libs so
+	    # that the program can be linked against the static library.
+	    echo
+	    $ECHO "*** Warning: This system can not link to static lib archive $lib."
+	    echo "*** I have the capability to make that library automatically link in when"
+	    echo "*** you link to this library.  But I can only do this if you have a"
+	    echo "*** shared version of the library, which you do not appear to have."
+	    if test "$module" = yes; then
+	      echo "*** But as you try to build a module library, libtool will still create "
+	      echo "*** a static module, that should work as long as the dlopening application"
+	      echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+	      if test -z "$global_symbol_pipe"; then
+		echo
+		echo "*** However, this would only work if libtool was able to extract symbol"
+		echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+		echo "*** not find such a program.  So, this module is probably useless."
+		echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	      fi
+	      if test "$build_old_libs" = no; then
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  else
+	    deplibs="$dir/$old_library $deplibs"
+	    link_static=yes
+	  fi
+	fi # link shared/static library?
+
+	if test "$linkmode" = lib; then
+	  if test -n "$dependency_libs" &&
+	     { test "$hardcode_into_libs" != yes ||
+	       test "$build_old_libs" = yes ||
+	       test "$link_static" = yes; }; then
+	    # Extract -R from dependency_libs
+	    temp_deplibs=
+	    for libdir in $dependency_libs; do
+	      case $libdir in
+	      -R*) func_stripname '-R' '' "$libdir"
+	           temp_xrpath=$func_stripname_result
+		   case " $xrpath " in
+		   *" $temp_xrpath "*) ;;
+		   *) func_append xrpath " $temp_xrpath";;
+		   esac;;
+	      *) func_append temp_deplibs " $libdir";;
+	      esac
+	    done
+	    dependency_libs="$temp_deplibs"
+	  fi
+
+	  func_append newlib_search_path " $absdir"
+	  # Link against this library
+	  test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+	  # ... and its dependency_libs
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    newdependency_libs="$deplib $newdependency_libs"
+	    case $deplib in
+              -L*) func_stripname '-L' '' "$deplib"
+                   func_resolve_sysroot "$func_stripname_result";;
+              *) func_resolve_sysroot "$deplib" ;;
+            esac
+	    if $opt_preserve_dup_deps ; then
+	      case "$tmp_libs " in
+	      *" $func_resolve_sysroot_result "*)
+                func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $func_resolve_sysroot_result"
+	  done
+
+	  if test "$link_all_deplibs" != no; then
+	    # Add the search paths of all dependency libraries
+	    for deplib in $dependency_libs; do
+	      path=
+	      case $deplib in
+	      -L*) path="$deplib" ;;
+	      *.la)
+	        func_resolve_sysroot "$deplib"
+	        deplib=$func_resolve_sysroot_result
+	        func_dirname "$deplib" "" "."
+		dir=$func_dirname_result
+		# We need an absolute path.
+		case $dir in
+		[\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+		*)
+		  absdir=`cd "$dir" && pwd`
+		  if test -z "$absdir"; then
+		    func_warning "cannot determine absolute directory name of \`$dir'"
+		    absdir="$dir"
+		  fi
+		  ;;
+		esac
+		if $GREP "^installed=no" $deplib > /dev/null; then
+		case $host in
+		*-*-darwin*)
+		  depdepl=
+		  eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+		  if test -n "$deplibrary_names" ; then
+		    for tmp in $deplibrary_names ; do
+		      depdepl=$tmp
+		    done
+		    if test -f "$absdir/$objdir/$depdepl" ; then
+		      depdepl="$absdir/$objdir/$depdepl"
+		      darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+                      if test -z "$darwin_install_name"; then
+                          darwin_install_name=`${OTOOL64} -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
+                      fi
+		      func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+		      func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}"
+		      path=
+		    fi
+		  fi
+		  ;;
+		*)
+		  path="-L$absdir/$objdir"
+		  ;;
+		esac
+		else
+		  eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  test -z "$libdir" && \
+		    func_fatal_error "\`$deplib' is not a valid libtool archive"
+		  test "$absdir" != "$libdir" && \
+		    func_warning "\`$deplib' seems to be moved"
+
+		  path="-L$absdir"
+		fi
+		;;
+	      esac
+	      case " $deplibs " in
+	      *" $path "*) ;;
+	      *) deplibs="$path $deplibs" ;;
+	      esac
+	    done
+	  fi # link_all_deplibs != no
+	fi # linkmode = lib
+      done # for deplib in $libs
+      if test "$pass" = link; then
+	if test "$linkmode" = "prog"; then
+	  compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+	  finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+	else
+	  compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	fi
+      fi
+      dependency_libs="$newdependency_libs"
+      if test "$pass" = dlpreopen; then
+	# Link the dlpreopened libraries before other libraries
+	for deplib in $save_deplibs; do
+	  deplibs="$deplib $deplibs"
+	done
+      fi
+      if test "$pass" != dlopen; then
+	if test "$pass" != conv; then
+	  # Make sure lib_search_path contains only unique directories.
+	  lib_search_path=
+	  for dir in $newlib_search_path; do
+	    case "$lib_search_path " in
+	    *" $dir "*) ;;
+	    *) func_append lib_search_path " $dir" ;;
+	    esac
+	  done
+	  newlib_search_path=
+	fi
+
+	if test "$linkmode,$pass" != "prog,link"; then
+	  vars="deplibs"
+	else
+	  vars="compile_deplibs finalize_deplibs"
+	fi
+	for var in $vars dependency_libs; do
+	  # Add libraries to $var in reverse order
+	  eval tmp_libs=\"\$$var\"
+	  new_libs=
+	  for deplib in $tmp_libs; do
+	    # FIXME: Pedantically, this is the right thing to do, so
+	    #        that some nasty dependency loop isn't accidentally
+	    #        broken:
+	    #new_libs="$deplib $new_libs"
+	    # Pragmatically, this seems to cause very few problems in
+	    # practice:
+	    case $deplib in
+	    -L*) new_libs="$deplib $new_libs" ;;
+	    -R*) ;;
+	    *)
+	      # And here is the reason: when a library appears more
+	      # than once as an explicit dependence of a library, or
+	      # is implicitly linked in more than once by the
+	      # compiler, it is considered special, and multiple
+	      # occurrences thereof are not removed.  Compare this
+	      # with having the same library being listed as a
+	      # dependency of multiple other libraries: in this case,
+	      # we know (pedantically, we assume) the library does not
+	      # need to be listed more than once, so we keep only the
+	      # last copy.  This is not always right, but it is rare
+	      # enough that we require users that really mean to play
+	      # such unportable linking tricks to link the library
+	      # using -Wl,-lname, so that libtool does not consider it
+	      # for duplicate removal.
+	      case " $specialdeplibs " in
+	      *" $deplib "*) new_libs="$deplib $new_libs" ;;
+	      *)
+		case " $new_libs " in
+		*" $deplib "*) ;;
+		*) new_libs="$deplib $new_libs" ;;
+		esac
+		;;
+	      esac
+	      ;;
+	    esac
+	  done
+	  tmp_libs=
+	  for deplib in $new_libs; do
+	    case $deplib in
+	    -L*)
+	      case " $tmp_libs " in
+	      *" $deplib "*) ;;
+	      *) func_append tmp_libs " $deplib" ;;
+	      esac
+	      ;;
+	    *) func_append tmp_libs " $deplib" ;;
+	    esac
+	  done
+	  eval $var=\"$tmp_libs\"
+	done # for var
+      fi
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs ; do
+	case " $predeps $postdeps $compiler_lib_search_path " in
+	*" $i "*)
+	  i=""
+	  ;;
+	esac
+	if test -n "$i" ; then
+	  func_append tmp_libs " $i"
+	fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test "$linkmode" = prog; then
+      dlfiles="$newdlfiles"
+    fi
+    if test "$linkmode" = prog || test "$linkmode" = lib; then
+      dlprefiles="$newdlprefiles"
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for archives"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for archives" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for archives"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for archives"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info/-version-number' is ignored for archives"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for archives"
+
+      test -n "$export_symbols$export_symbols_regex" && \
+	func_warning "\`-export-symbols' is ignored for archives"
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs="$output"
+      func_append objs "$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case $outputname in
+      lib*)
+	func_stripname 'lib' '.la' "$outputname"
+	name=$func_stripname_result
+	eval shared_ext=\"$shrext_cmds\"
+	eval libname=\"$libname_spec\"
+	;;
+      *)
+	test "$module" = no && \
+	  func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+	if test "$need_lib_prefix" != no; then
+	  # Add the "lib" prefix for modules if required
+	  func_stripname '' '.la' "$outputname"
+	  name=$func_stripname_result
+	  eval shared_ext=\"$shrext_cmds\"
+	  eval libname=\"$libname_spec\"
+	else
+	  func_stripname '' '.la' "$outputname"
+	  libname=$func_stripname_result
+	fi
+	;;
+      esac
+
+      if test -n "$objs"; then
+	if test "$deplibs_check_method" != pass_all; then
+	  func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+	else
+	  echo
+	  $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+	  $ECHO "*** objects $objs is not portable!"
+	  func_append libobjs " $objs"
+	fi
+      fi
+
+      test "$dlself" != no && \
+	func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+      set dummy $rpath
+      shift
+      test "$#" -gt 1 && \
+	func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+      install_libdir="$1"
+
+      oldlibs=
+      if test -z "$rpath"; then
+	if test "$build_libtool_libs" = yes; then
+	  # Building a libtool convenience library.
+	  # Some compilers have problems with a `.al' extension so
+	  # convenience libraries should have the same extension an
+	  # archive normally would.
+	  oldlibs="$output_objdir/$libname.$libext $oldlibs"
+	  build_libtool_libs=convenience
+	  build_old_libs=yes
+	fi
+
+	test -n "$vinfo" && \
+	  func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+	test -n "$release" && \
+	  func_warning "\`-release' is ignored for convenience libraries"
+      else
+
+	# Parse the version information argument.
+	save_ifs="$IFS"; IFS=':'
+	set dummy $vinfo 0 0 0
+	shift
+	IFS="$save_ifs"
+
+	test -n "$7" && \
+	  func_fatal_help "too many parameters to \`-version-info'"
+
+	# convert absolute version numbers to libtool ages
+	# this retains compatibility with .la files and attempts
+	# to make the code below a bit more comprehensible
+
+	case $vinfo_number in
+	yes)
+	  number_major="$1"
+	  number_minor="$2"
+	  number_revision="$3"
+	  #
+	  # There are really only two kinds -- those that
+	  # use the current revision as the major version
+	  # and those that subtract age and use age as
+	  # a minor version.  But, then there is irix
+	  # which has an extra 1 added just for fun
+	  #
+	  case $version_type in
+	  # correct linux to gnu/linux during the next big refactor
+	  darwin|linux|osf|windows|none)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_revision"
+	    ;;
+	  freebsd-aout|freebsd-elf|qnx|sunos)
+	    current="$number_major"
+	    revision="$number_minor"
+	    age="0"
+	    ;;
+	  irix|nonstopux)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_minor"
+	    lt_irix_increment=no
+	    ;;
+	  *)
+	    func_fatal_configuration "$modename: unknown library version type \`$version_type'"
+	    ;;
+	  esac
+	  ;;
+	no)
+	  current="$1"
+	  revision="$2"
+	  age="$3"
+	  ;;
+	esac
+
+	# Check that each of the things are valid numbers.
+	case $current in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "CURRENT \`$current' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $revision in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "REVISION \`$revision' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $age in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "AGE \`$age' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	if test "$age" -gt "$current"; then
+	  func_error "AGE \`$age' is greater than the current interface number \`$current'"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	fi
+
+	# Calculate the version variables.
+	major=
+	versuffix=
+	verstring=
+	case $version_type in
+	none) ;;
+
+	darwin)
+	  # Like Linux, but with the current version available in
+	  # verstring for coding it into the library header
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  # Darwin ld doesn't like 0 for these options...
+	  func_arith $current + 1
+	  minor_current=$func_arith_result
+	  xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+	  ;;
+
+	freebsd-aout)
+	  major=".$current"
+	  versuffix=".$current.$revision";
+	  ;;
+
+	freebsd-elf)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	irix | nonstopux)
+	  if test "X$lt_irix_increment" = "Xno"; then
+	    func_arith $current - $age
+	  else
+	    func_arith $current - $age + 1
+	  fi
+	  major=$func_arith_result
+
+	  case $version_type in
+	    nonstopux) verstring_prefix=nonstopux ;;
+	    *)         verstring_prefix=sgi ;;
+	  esac
+	  verstring="$verstring_prefix$major.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$revision
+	  while test "$loop" -ne 0; do
+	    func_arith $revision - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring_prefix$major.$iface:$verstring"
+	  done
+
+	  # Before this point, $major must not contain `.'.
+	  major=.$major
+	  versuffix="$major.$revision"
+	  ;;
+
+	linux) # correct to gnu/linux during the next big refactor
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  ;;
+
+	osf)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=".$current.$age.$revision"
+	  verstring="$current.$age.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$age
+	  while test "$loop" -ne 0; do
+	    func_arith $current - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring:${iface}.0"
+	  done
+
+	  # Make executables depend on our current version.
+	  func_append verstring ":${current}.0"
+	  ;;
+
+	qnx)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	sunos)
+	  major=".$current"
+	  versuffix=".$current.$revision"
+	  ;;
+
+	windows)
+	  # Use '-' rather than '.', since we only want one
+	  # extension on DOS 8.3 filesystems.
+	  func_arith $current - $age
+	  major=$func_arith_result
+	  versuffix="-$major"
+	  ;;
+
+	*)
+	  func_fatal_configuration "unknown library version type \`$version_type'"
+	  ;;
+	esac
+
+	# Clear the version info if we defaulted, and they specified a release.
+	if test -z "$vinfo" && test -n "$release"; then
+	  major=
+	  case $version_type in
+	  darwin)
+	    # we can't check for "0.0" in archive_cmds due to quoting
+	    # problems, so we reset it completely
+	    verstring=
+	    ;;
+	  *)
+	    verstring="0.0"
+	    ;;
+	  esac
+	  if test "$need_version" = no; then
+	    versuffix=
+	  else
+	    versuffix=".0.0"
+	  fi
+	fi
+
+	# Remove version info from name if versioning should be avoided
+	if test "$avoid_version" = yes && test "$need_version" = no; then
+	  major=
+	  versuffix=
+	  verstring=""
+	fi
+
+	# Check to see if the archive will have undefined symbols.
+	if test "$allow_undefined" = yes; then
+	  if test "$allow_undefined_flag" = unsupported; then
+	    func_warning "undefined symbols not allowed in $host shared libraries"
+	    build_libtool_libs=no
+	    build_old_libs=yes
+	  fi
+	else
+	  # Don't allow undefined symbols.
+	  allow_undefined_flag="$no_undefined_flag"
+	fi
+
+      fi
+
+      func_generate_dlsyms "$libname" "$libname" "yes"
+      func_append libobjs " $symfileobj"
+      test "X$libobjs" = "X " && libobjs=
+
+      if test "$opt_mode" != relink; then
+	# Remove our outputs, but don't remove object files since they
+	# may have been created when compiling PIC objects.
+	removelist=
+	tempremovelist=`$ECHO "$output_objdir/*"`
+	for p in $tempremovelist; do
+	  case $p in
+	    *.$objext | *.gcno)
+	       ;;
+	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+	       if test "X$precious_files_regex" != "X"; then
+		 if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+		 then
+		   continue
+		 fi
+	       fi
+	       func_append removelist " $p"
+	       ;;
+	    *) ;;
+	  esac
+	done
+	test -n "$removelist" && \
+	  func_show_eval "${RM}r \$removelist"
+      fi
+
+      # Now set the variables for building old libraries.
+      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+	func_append oldlibs " $output_objdir/$libname.$libext"
+
+	# Transform .lo files to .o files.
+	oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #	lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+      #	deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+      #	dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+      #done
+
+      if test -n "$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	temp_xrpath=
+	for libdir in $xrpath; do
+	  func_replace_sysroot "$libdir"
+	  func_append temp_xrpath " -R$func_replace_sysroot_result"
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+	if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+	  dependency_libs="$temp_xrpath $dependency_libs"
+	fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles="$dlfiles"
+      dlfiles=
+      for lib in $old_dlfiles; do
+	case " $dlprefiles $dlfiles " in
+	*" $lib "*) ;;
+	*) func_append dlfiles " $lib" ;;
+	esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles="$dlprefiles"
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+	case "$dlprefiles " in
+	*" $lib "*) ;;
+	*) func_append dlprefiles " $lib" ;;
+	esac
+      done
+
+      if test "$build_libtool_libs" = yes; then
+	if test -n "$rpath"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # these systems don't actually have a c library (as such)!
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C library is in the System framework
+	    func_append deplibs " System.ltframework"
+	    ;;
+	  *-*-netbsd*)
+	    # Don't link with libc until the a.out ld.so is fixed.
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    ;;
+	  *)
+	    # Add libc to deplibs on all other systems if necessary.
+	    if test "$build_libtool_need_lc" = "yes"; then
+	      func_append deplibs " -lc"
+	    fi
+	    ;;
+	  esac
+	fi
+
+	# Transform deplibs into only deplibs that can be linked in shared.
+	name_save=$name
+	libname_save=$libname
+	release_save=$release
+	versuffix_save=$versuffix
+	major_save=$major
+	# I'm not sure if I'm treating the release correctly.  I think
+	# release should show up in the -l (ie -lgmp5) so we don't want to
+	# add it in twice.  Is that correct?
+	release=""
+	versuffix=""
+	major=""
+	newdeplibs=
+	droppeddeps=no
+	case $deplibs_check_method in
+	pass_all)
+	  # Don't check for shared/static.  Everything works.
+	  # This might be a little naive.  We might want to check
+	  # whether the library exists or not.  But this is on
+	  # osf3 & osf4 and I'm not really sure... Just
+	  # implementing what was already the behavior.
+	  newdeplibs=$deplibs
+	  ;;
+	test_compile)
+	  # This code stresses the "libraries are programs" paradigm to its
+	  # limits. Maybe even breaks it.  We compile a program, linking it
+	  # against the deplibs as a proxy for the library.  Then we can check
+	  # whether they linked in statically or dynamically with ldd.
+	  $opt_dry_run || $RM conftest.c
+	  cat > conftest.c <<EOF
+	  int main() { return 0; }
+EOF
+	  $opt_dry_run || $RM conftest
+	  if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+	    ldd_output=`ldd conftest`
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		  case " $predeps $postdeps " in
+		  *" $i "*)
+		    func_append newdeplibs " $i"
+		    i=""
+		    ;;
+		  esac
+		fi
+		if test -n "$i" ; then
+		  libname=`eval "\\$ECHO \"$libname_spec\""`
+		  deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		  set dummy $deplib_matches; shift
+		  deplib_match=$1
+		  if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		    func_append newdeplibs " $i"
+		  else
+		    droppeddeps=yes
+		    echo
+		    $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		    echo "*** I have the capability to make that library automatically link in when"
+		    echo "*** you link to this library.  But I can only do this if you have a"
+		    echo "*** shared version of the library, which I believe you do not have"
+		    echo "*** because a test_compile did reveal that the linker did not use it for"
+		    echo "*** its dynamic dependency list that programs get resolved with at runtime."
+		  fi
+		fi
+		;;
+	      *)
+		func_append newdeplibs " $i"
+		;;
+	      esac
+	    done
+	  else
+	    # Error occurred in the first compile.  Let's try to salvage
+	    # the situation: Compile a separate program for each library.
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		$opt_dry_run || $RM conftest
+		if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+		  ldd_output=`ldd conftest`
+		  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		    case " $predeps $postdeps " in
+		    *" $i "*)
+		      func_append newdeplibs " $i"
+		      i=""
+		      ;;
+		    esac
+		  fi
+		  if test -n "$i" ; then
+		    libname=`eval "\\$ECHO \"$libname_spec\""`
+		    deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		    set dummy $deplib_matches; shift
+		    deplib_match=$1
+		    if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		      func_append newdeplibs " $i"
+		    else
+		      droppeddeps=yes
+		      echo
+		      $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		      echo "*** I have the capability to make that library automatically link in when"
+		      echo "*** you link to this library.  But I can only do this if you have a"
+		      echo "*** shared version of the library, which you do not appear to have"
+		      echo "*** because a test_compile did reveal that the linker did not use this one"
+		      echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+		    fi
+		  fi
+		else
+		  droppeddeps=yes
+		  echo
+		  $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
+		  echo "*** make it link in!  You will probably need to install it or some"
+		  echo "*** library that it depends on before this library will be fully"
+		  echo "*** functional.  Installing it before continuing would be even better."
+		fi
+		;;
+	      *)
+		func_append newdeplibs " $i"
+		;;
+	      esac
+	    done
+	  fi
+	  ;;
+	file_magic*)
+	  set dummy $deplibs_check_method; shift
+	  file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		if test -n "$file_magic_glob"; then
+		  libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+		else
+		  libnameglob=$libname
+		fi
+		test "$want_nocaseglob" = yes && nocaseglob=`shopt -p nocaseglob`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  if test "$want_nocaseglob" = yes; then
+		    shopt -s nocaseglob
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		    $nocaseglob
+		  else
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		  fi
+		  for potent_lib in $potential_libs; do
+		      # Follow soft links.
+		      if ls -lLd "$potent_lib" 2>/dev/null |
+			 $GREP " -> " >/dev/null; then
+			continue
+		      fi
+		      # The statement above tries to avoid entering an
+		      # endless loop below, in case of cyclic links.
+		      # We might still enter an endless loop, since a link
+		      # loop can be closed while we follow links,
+		      # but so what?
+		      potlib="$potent_lib"
+		      while test -h "$potlib" 2>/dev/null; do
+			potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+			case $potliblink in
+			[\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+			*) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+			esac
+		      done
+		      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+			 $SED -e 10q |
+			 $EGREP "$file_magic_regex" > /dev/null; then
+			func_append newdeplibs " $a_deplib"
+			a_deplib=""
+			break 2
+		      fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a file magic. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	match_pattern*)
+	  set dummy $deplibs_check_method; shift
+	  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		    potlib="$potent_lib" # see symlink-check above in file_magic test
+		    if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+		       $EGREP "$match_pattern_regex" > /dev/null; then
+		      func_append newdeplibs " $a_deplib"
+		      a_deplib=""
+		      break 2
+		    fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a regex pattern. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	none | unknown | *)
+	  newdeplibs=""
+	  tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+	  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	    for i in $predeps $postdeps ; do
+	      # can't use Xsed below, because $i might contain '/'
+	      tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+	    done
+	  fi
+	  case $tmp_deplibs in
+	  *[!\	\ ]*)
+	    echo
+	    if test "X$deplibs_check_method" = "Xnone"; then
+	      echo "*** Warning: inter-library dependencies are not supported in this platform."
+	    else
+	      echo "*** Warning: inter-library dependencies are not known to be supported."
+	    fi
+	    echo "*** All declared inter-library dependencies are being dropped."
+	    droppeddeps=yes
+	    ;;
+	  esac
+	  ;;
+	esac
+	versuffix=$versuffix_save
+	major=$major_save
+	release=$release_save
+	libname=$libname_save
+	name=$name_save
+
+	case $host in
+	*-*-rhapsody* | *-*-darwin1.[012])
+	  # On Rhapsody replace the C library with the System framework
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+	  ;;
+	esac
+
+	if test "$droppeddeps" = yes; then
+	  if test "$module" = yes; then
+	    echo
+	    echo "*** Warning: libtool could not satisfy all declared inter-library"
+	    $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
+	    echo "*** a static module, that should work as long as the dlopening"
+	    echo "*** application is linked with the -dlopen flag."
+	    if test -z "$global_symbol_pipe"; then
+	      echo
+	      echo "*** However, this would only work if libtool was able to extract symbol"
+	      echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+	      echo "*** not find such a program.  So, this module is probably useless."
+	      echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	    fi
+	    if test "$build_old_libs" = no; then
+	      oldlibs="$output_objdir/$libname.$libext"
+	      build_libtool_libs=module
+	      build_old_libs=yes
+	    else
+	      build_libtool_libs=no
+	    fi
+	  else
+	    echo "*** The inter-library dependencies that have been dropped here will be"
+	    echo "*** automatically added whenever a program is linked with this library"
+	    echo "*** or is declared to -dlopen it."
+
+	    if test "$allow_undefined" = no; then
+	      echo
+	      echo "*** Since this library must not contain undefined symbols,"
+	      echo "*** because either the platform does not support them or"
+	      echo "*** it was explicitly requested with -no-undefined,"
+	      echo "*** libtool will only create a static version of it."
+	      if test "$build_old_libs" = no; then
+		oldlibs="$output_objdir/$libname.$libext"
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  fi
+	fi
+	# Done checking deplibs!
+	deplibs=$newdeplibs
+      fi
+      # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+      case $host in
+	*-*-darwin*)
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  ;;
+      esac
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      deplibs="$new_libs"
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test "$build_libtool_libs" = yes; then
+	# Remove ${wl} instances when linking with ld.
+	# FIXME: should test the right _cmds variable.
+	case $archive_cmds in
+	  *\$LD\ *) wl= ;;
+        esac
+	if test "$hardcode_into_libs" = yes; then
+	  # Hardcode the library paths
+	  hardcode_libdirs=
+	  dep_rpath=
+	  rpath="$finalize_rpath"
+	  test "$opt_mode" != relink && rpath="$compile_rpath$rpath"
+	  for libdir in $rpath; do
+	    if test -n "$hardcode_libdir_flag_spec"; then
+	      if test -n "$hardcode_libdir_separator"; then
+		func_replace_sysroot "$libdir"
+		libdir=$func_replace_sysroot_result
+		if test -z "$hardcode_libdirs"; then
+		  hardcode_libdirs="$libdir"
+		else
+		  # Just accumulate the unique libdirs.
+		  case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+		  *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		    ;;
+		  *)
+		    func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		    ;;
+		  esac
+		fi
+	      else
+		eval flag=\"$hardcode_libdir_flag_spec\"
+		func_append dep_rpath " $flag"
+	      fi
+	    elif test -n "$runpath_var"; then
+	      case "$perm_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append perm_rpath " $libdir" ;;
+	      esac
+	    fi
+	  done
+	  # Substitute the hardcoded libdirs into the rpath.
+	  if test -n "$hardcode_libdir_separator" &&
+	     test -n "$hardcode_libdirs"; then
+	    libdir="$hardcode_libdirs"
+	    eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+	  fi
+	  if test -n "$runpath_var" && test -n "$perm_rpath"; then
+	    # We should set the runpath_var.
+	    rpath=
+	    for dir in $perm_rpath; do
+	      func_append rpath "$dir:"
+	    done
+	    eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+	  fi
+	  test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+	fi
+
+	shlibpath="$finalize_shlibpath"
+	test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+	if test -n "$shlibpath"; then
+	  eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+	fi
+
+	# Get the real and link names of the library.
+	eval shared_ext=\"$shrext_cmds\"
+	eval library_names=\"$library_names_spec\"
+	set dummy $library_names
+	shift
+	realname="$1"
+	shift
+
+	if test -n "$soname_spec"; then
+	  eval soname=\"$soname_spec\"
+	else
+	  soname="$realname"
+	fi
+	if test -z "$dlname"; then
+	  dlname=$soname
+	fi
+
+	lib="$output_objdir/$realname"
+	linknames=
+	for link
+	do
+	  func_append linknames " $link"
+	done
+
+	# Use standard objects if they are pic
+	test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	test "X$libobjs" = "X " && libobjs=
+
+	delfiles=
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+	  export_symbols="$output_objdir/$libname.uexp"
+	  func_append delfiles " $export_symbols"
+	fi
+
+	orig_export_symbols=
+	case $host_os in
+	cygwin* | mingw* | cegcc*)
+	  if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+	    # exporting using user supplied symfile
+	    if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+	      # and it's NOT already a .def file. Must figure out
+	      # which of the given symbols are data symbols and tag
+	      # them as such. So, trigger use of export_symbols_cmds.
+	      # export_symbols gets reassigned inside the "prepare
+	      # the list of exported symbols" if statement, so the
+	      # include_expsyms logic still works.
+	      orig_export_symbols="$export_symbols"
+	      export_symbols=
+	      always_export_symbols=yes
+	    fi
+	  fi
+	  ;;
+	esac
+
+	# Prepare the list of exported symbols
+	if test -z "$export_symbols"; then
+	  if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+	    func_verbose "generating symbol list for \`$libname.la'"
+	    export_symbols="$output_objdir/$libname.exp"
+	    $opt_dry_run || $RM $export_symbols
+	    cmds=$export_symbols_cmds
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd1 in $cmds; do
+	      IFS="$save_ifs"
+	      # Take the normal branch if the nm_file_list_spec branch
+	      # doesn't work or if tool conversion is not needed.
+	      case $nm_file_list_spec~$to_tool_file_cmd in
+		*~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+		  try_normal_branch=yes
+		  eval cmd=\"$cmd1\"
+		  func_len " $cmd"
+		  len=$func_len_result
+		  ;;
+		*)
+		  try_normal_branch=no
+		  ;;
+	      esac
+	      if test "$try_normal_branch" = yes \
+		 && { test "$len" -lt "$max_cmd_len" \
+		      || test "$max_cmd_len" -le -1; }
+	      then
+		func_show_eval "$cmd" 'exit $?'
+		skipped_export=false
+	      elif test -n "$nm_file_list_spec"; then
+		func_basename "$output"
+		output_la=$func_basename_result
+		save_libobjs=$libobjs
+		save_output=$output
+		output=${output_objdir}/${output_la}.nm
+		func_to_tool_file "$output"
+		libobjs=$nm_file_list_spec$func_to_tool_file_result
+		func_append delfiles " $output"
+		func_verbose "creating $NM input file list: $output"
+		for obj in $save_libobjs; do
+		  func_to_tool_file "$obj"
+		  $ECHO "$func_to_tool_file_result"
+		done > "$output"
+		eval cmd=\"$cmd1\"
+		func_show_eval "$cmd" 'exit $?'
+		output=$save_output
+		libobjs=$save_libobjs
+		skipped_export=false
+	      else
+		# The command line is too long to execute in one step.
+		func_verbose "using reloadable object file for export list..."
+		skipped_export=:
+		# Break out early, otherwise skipped_export may be
+		# set to false by a later but shorter cmd.
+		break
+	      fi
+	    done
+	    IFS="$save_ifs"
+	    if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+	fi
+
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  tmp_export_symbols="$export_symbols"
+	  test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	  $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	fi
+
+	if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+	  # The given exports_symbols file has to be filtered, so filter it.
+	  func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	  # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	  # 's' commands which not all seds can handle. GNU sed should be fine
+	  # though. Also, the filter scales superlinearly with the number of
+	  # global variables. join(1) would be nice here, but unfortunately
+	  # isn't a blessed tool.
+	  $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	  func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	  export_symbols=$output_objdir/$libname.def
+	  $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	fi
+
+	tmp_deplibs=
+	for test_deplib in $deplibs; do
+	  case " $convenience " in
+	  *" $test_deplib "*) ;;
+	  *)
+	    func_append tmp_deplibs " $test_deplib"
+	    ;;
+	  esac
+	done
+	deplibs="$tmp_deplibs"
+
+	if test -n "$convenience"; then
+	  if test -n "$whole_archive_flag_spec" &&
+	    test "$compiler_needs_object" = yes &&
+	    test -z "$libobjs"; then
+	    # extract the archives, so we have objects to list.
+	    # TODO: could optimize this to just extract one archive.
+	    whole_archive_flag_spec=
+	  fi
+	  if test -n "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  else
+	    gentop="$output_objdir/${outputname}x"
+	    func_append generated " $gentop"
+
+	    func_extract_archives $gentop $convenience
+	    func_append libobjs " $func_extract_archives_result"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	fi
+
+	if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+	  eval flag=\"$thread_safe_flag_spec\"
+	  func_append linker_flags " $flag"
+	fi
+
+	# Make a backup of the uninstalled library when relinking
+	if test "$opt_mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+	fi
+
+	# Do each of the archive commands.
+	if test "$module" = yes && test -n "$module_cmds" ; then
+	  if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	    eval test_cmds=\"$module_expsym_cmds\"
+	    cmds=$module_expsym_cmds
+	  else
+	    eval test_cmds=\"$module_cmds\"
+	    cmds=$module_cmds
+	  fi
+	else
+	  if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	    eval test_cmds=\"$archive_expsym_cmds\"
+	    cmds=$archive_expsym_cmds
+	  else
+	    eval test_cmds=\"$archive_cmds\"
+	    cmds=$archive_cmds
+	  fi
+	fi
+
+	if test "X$skipped_export" != "X:" &&
+	   func_len " $test_cmds" &&
+	   len=$func_len_result &&
+	   test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  :
+	else
+	  # The command line is too long to link in one step, link piecewise
+	  # or, if using GNU ld and skipped_export is not :, use a linker
+	  # script.
+
+	  # Save the value of $output and $libobjs because we want to
+	  # use them later.  If we have whole_archive_flag_spec, we
+	  # want to use save_libobjs as it was before
+	  # whole_archive_flag_spec was expanded, because we can't
+	  # assume the linker understands whole_archive_flag_spec.
+	  # This may have to be revisited, in case too many
+	  # convenience libraries get linked in and end up exceeding
+	  # the spec.
+	  if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	  fi
+	  save_output=$output
+	  func_basename "$output"
+	  output_la=$func_basename_result
+
+	  # Clear the reloadable object creation command queue and
+	  # initialize k to one.
+	  test_cmds=
+	  concat_cmds=
+	  objlist=
+	  last_robj=
+	  k=1
+
+	  if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+	    output=${output_objdir}/${output_la}.lnkscript
+	    func_verbose "creating GNU ld script: $output"
+	    echo 'INPUT (' > $output
+	    for obj in $save_libobjs
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    echo ')' >> $output
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$func_to_tool_file_result
+	  elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+	    output=${output_objdir}/${output_la}.lnk
+	    func_verbose "creating linker input file list: $output"
+	    : > $output
+	    set x $save_libobjs
+	    shift
+	    firstobj=
+	    if test "$compiler_needs_object" = yes; then
+	      firstobj="$1 "
+	      shift
+	    fi
+	    for obj
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+	  else
+	    if test -n "$save_libobjs"; then
+	      func_verbose "creating reloadable object files..."
+	      output=$output_objdir/$output_la-${k}.$objext
+	      eval test_cmds=\"$reload_cmds\"
+	      func_len " $test_cmds"
+	      len0=$func_len_result
+	      len=$len0
+
+	      # Loop over the list of objects to be linked.
+	      for obj in $save_libobjs
+	      do
+		func_len " $obj"
+		func_arith $len + $func_len_result
+		len=$func_arith_result
+		if test "X$objlist" = X ||
+		   test "$len" -lt "$max_cmd_len"; then
+		  func_append objlist " $obj"
+		else
+		  # The command $test_cmds is almost too long, add a
+		  # command to the queue.
+		  if test "$k" -eq 1 ; then
+		    # The first file doesn't have a previous command to add.
+		    reload_objs=$objlist
+		    eval concat_cmds=\"$reload_cmds\"
+		  else
+		    # All subsequent reloadable object files will link in
+		    # the last one created.
+		    reload_objs="$objlist $last_robj"
+		    eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+		  fi
+		  last_robj=$output_objdir/$output_la-${k}.$objext
+		  func_arith $k + 1
+		  k=$func_arith_result
+		  output=$output_objdir/$output_la-${k}.$objext
+		  objlist=" $obj"
+		  func_len " $last_robj"
+		  func_arith $len0 + $func_len_result
+		  len=$func_arith_result
+		fi
+	      done
+	      # Handle the remaining objects by creating one last
+	      # reloadable object file.  All subsequent reloadable object
+	      # files will link in the last one created.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      reload_objs="$objlist $last_robj"
+	      eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
+	      if test -n "$last_robj"; then
+	        eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+	      fi
+	      func_append delfiles " $output"
+
+	    else
+	      output=
+	    fi
+
+	    if ${skipped_export-false}; then
+	      func_verbose "generating symbol list for \`$libname.la'"
+	      export_symbols="$output_objdir/$libname.exp"
+	      $opt_dry_run || $RM $export_symbols
+	      libobjs=$output
+	      # Append the command to create the export file.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+	      if test -n "$last_robj"; then
+		eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+	      fi
+	    fi
+
+	    test -n "$save_libobjs" &&
+	      func_verbose "creating a temporary reloadable object file: $output"
+
+	    # Loop through the commands generated above and execute them.
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd in $concat_cmds; do
+	      IFS="$save_ifs"
+	      $opt_silent || {
+		  func_quote_for_expand "$cmd"
+		  eval "func_echo $func_quote_for_expand_result"
+	      }
+	      $opt_dry_run || eval "$cmd" || {
+		lt_exit=$?
+
+		# Restore the uninstalled library and exit
+		if test "$opt_mode" = relink; then
+		  ( cd "$output_objdir" && \
+		    $RM "${realname}T" && \
+		    $MV "${realname}U" "$realname" )
+		fi
+
+		exit $lt_exit
+	      }
+	    done
+	    IFS="$save_ifs"
+
+	    if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+
+          if ${skipped_export-false}; then
+	    if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	      tmp_export_symbols="$export_symbols"
+	      test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	      $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	    fi
+
+	    if test -n "$orig_export_symbols"; then
+	      # The given exports_symbols file has to be filtered, so filter it.
+	      func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	      # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	      # 's' commands which not all seds can handle. GNU sed should be fine
+	      # though. Also, the filter scales superlinearly with the number of
+	      # global variables. join(1) would be nice here, but unfortunately
+	      # isn't a blessed tool.
+	      $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	      func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	      export_symbols=$output_objdir/$libname.def
+	      $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	    fi
+	  fi
+
+	  libobjs=$output
+	  # Restore the value of output.
+	  output=$save_output
+
+	  if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	  # Expand the library linking commands again to reset the
+	  # value of $libobjs for piecewise linking.
+
+	  # Do each of the archive commands.
+	  if test "$module" = yes && test -n "$module_cmds" ; then
+	    if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	      cmds=$module_expsym_cmds
+	    else
+	      cmds=$module_cmds
+	    fi
+	  else
+	    if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	      cmds=$archive_expsym_cmds
+	    else
+	      cmds=$archive_cmds
+	    fi
+	  fi
+	fi
+
+	if test -n "$delfiles"; then
+	  # Append the command to remove temporary files to $cmds.
+	  eval cmds=\"\$cmds~\$RM $delfiles\"
+	fi
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append libobjs " $func_extract_archives_result"
+	  test "X$libobjs" = "X " && libobjs=
+	fi
+
+	save_ifs="$IFS"; IFS='~'
+	for cmd in $cmds; do
+	  IFS="$save_ifs"
+	  eval cmd=\"$cmd\"
+	  $opt_silent || {
+	    func_quote_for_expand "$cmd"
+	    eval "func_echo $func_quote_for_expand_result"
+	  }
+	  $opt_dry_run || eval "$cmd" || {
+	    lt_exit=$?
+
+	    # Restore the uninstalled library and exit
+	    if test "$opt_mode" = relink; then
+	      ( cd "$output_objdir" && \
+	        $RM "${realname}T" && \
+		$MV "${realname}U" "$realname" )
+	    fi
+
+	    exit $lt_exit
+	  }
+	done
+	IFS="$save_ifs"
+
+	# Restore the uninstalled library and exit
+	if test "$opt_mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+	  if test -n "$convenience"; then
+	    if test -z "$whole_archive_flag_spec"; then
+	      func_show_eval '${RM}r "$gentop"'
+	    fi
+	  fi
+
+	  exit $EXIT_SUCCESS
+	fi
+
+	# Create links to the real library.
+	for linkname in $linknames; do
+	  if test "$realname" != "$linkname"; then
+	    func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+	  fi
+	done
+
+	# If -module or -export-dynamic was specified, set the dlname.
+	if test "$module" = yes || test "$export_dynamic" = yes; then
+	  # On all known operating systems, these are identical.
+	  dlname="$soname"
+	fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for objects"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for objects" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for objects"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for objects"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for objects"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for objects"
+
+      case $output in
+      *.lo)
+	test -n "$objs$old_deplibs" && \
+	  func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+	libobj=$output
+	func_lo2o "$libobj"
+	obj=$func_lo2o_result
+	;;
+      *)
+	libobj=
+	obj="$output"
+	;;
+      esac
+
+      # Delete the old objects.
+      $opt_dry_run || $RM $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # reload_cmds runs $LD directly, so let us get rid of
+      # -Wl from whole_archive_flag_spec and hope we can get by with
+      # turning comma into space..
+      wl=
+
+      if test -n "$convenience"; then
+	if test -n "$whole_archive_flag_spec"; then
+	  eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+	  reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+	else
+	  gentop="$output_objdir/${obj}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $convenience
+	  reload_conv_objs="$reload_objs $func_extract_archives_result"
+	fi
+      fi
+
+      # If we're not building shared, we need to use non_pic_objs
+      test "$build_libtool_libs" != yes && libobjs="$non_pic_objects"
+
+      # Create the old-style object.
+      reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+      output="$obj"
+      func_execute_cmds "$reload_cmds" 'exit $?'
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$build_libtool_libs" != yes; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	# Create an invalid libtool object if no PIC, so that we don't
+	# accidentally link it into a program.
+	# $show "echo timestamp > $libobj"
+	# $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+	exit $EXIT_SUCCESS
+      fi
+
+      if test -n "$pic_flag" || test "$pic_mode" != default; then
+	# Only do commands if we really have different PIC objects.
+	reload_objs="$libobjs $reload_conv_objs"
+	output="$libobj"
+	func_execute_cmds "$reload_cmds" 'exit $?'
+      fi
+
+      if test -n "$gentop"; then
+	func_show_eval '${RM}r "$gentop"'
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+	*cygwin*) func_stripname '' '.exe' "$output"
+	          output=$func_stripname_result.exe;;
+      esac
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for programs"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for programs"
+
+      test "$preload" = yes \
+        && test "$dlopen_support" = unknown \
+	&& test "$dlopen_self" = unknown \
+	&& test "$dlopen_self_static" = unknown && \
+	  func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+	# On Rhapsody replace the C library is the System framework
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	;;
+      esac
+
+      case $host in
+      *-*-darwin*)
+	# Don't allow lazy linking, it breaks C++ global constructors
+	# But is supposedly fixed on 10.4 or later (yay!).
+	if test "$tagname" = CXX ; then
+	  case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+	    10.[0123])
+	      func_append compile_command " ${wl}-bind_at_load"
+	      func_append finalize_command " ${wl}-bind_at_load"
+	    ;;
+	  esac
+	fi
+	# Time to change all our "foo.ltframework" stuff back to "-framework foo"
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	;;
+      esac
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $compile_deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $compile_deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      compile_deplibs="$new_libs"
+
+
+      func_append compile_command " $compile_deplibs"
+      func_append finalize_command " $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	for libdir in $rpath $xrpath; do
+	  # This is the magic to use -rpath.
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append perm_rpath " $libdir" ;;
+	  esac
+	fi
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$libdir:"*) ;;
+	  ::) dllsearchpath=$libdir;;
+	  *) func_append dllsearchpath ":$libdir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath="$rpath"
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$finalize_perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_perm_rpath " $libdir" ;;
+	  esac
+	fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath="$rpath"
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+	# Transform all the library objects into standard objects.
+	compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+      fi
+
+      func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+      # template prelinking step
+      if test -n "$prelink_cmds"; then
+	func_execute_cmds "$prelink_cmds" 'exit $?'
+      fi
+
+      wrappers_required=yes
+      case $host in
+      *cegcc* | *mingw32ce*)
+        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+        wrappers_required=no
+        ;;
+      *cygwin* | *mingw* )
+        if test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      *)
+        if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      esac
+      if test "$wrappers_required" = no; then
+	# Replace the output file specification.
+	compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	link_command="$compile_command$compile_rpath"
+
+	# We have no uninstalled library dependencies, so finalize right now.
+	exit_status=0
+	func_show_eval "$link_command" 'exit_status=$?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	# Delete the generated files.
+	if test -f "$output_objdir/${outputname}S.${objext}"; then
+	  func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+	fi
+
+	exit $exit_status
+      fi
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+	compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+	finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+	if test -n "$perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+	if test -n "$finalize_perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $finalize_perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+      fi
+
+      if test "$no_install" = yes; then
+	# We don't need to create a wrapper script.
+	link_command="$compile_var$compile_command$compile_rpath"
+	# Replace the output file specification.
+	link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	# Delete the old output file.
+	$opt_dry_run || $RM $output
+	# Link the executable and exit
+	func_show_eval "$link_command" 'exit $?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$hardcode_action" = relink; then
+	# Fast installation is not supported
+	link_command="$compile_var$compile_command$compile_rpath"
+	relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+	func_warning "this platform does not like uninstalled shared libraries"
+	func_warning "\`$output' will be relinked during installation"
+      else
+	if test "$fast_install" != no; then
+	  link_command="$finalize_var$compile_command$finalize_rpath"
+	  if test "$fast_install" = yes; then
+	    relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+	  else
+	    # fast_install is set to needless
+	    relink_command=
+	  fi
+	else
+	  link_command="$compile_var$compile_command$compile_rpath"
+	  relink_command="$finalize_var$finalize_command$finalize_rpath"
+	fi
+      fi
+
+      # Replace the output file specification.
+      link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      func_show_eval "$link_command" 'exit $?'
+
+      if test -n "$postlink_cmds"; then
+	func_to_tool_file "$output_objdir/$outputname"
+	postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	func_execute_cmds "$postlink_cmds" 'exit $?'
+      fi
+
+      # Now create the wrapper script.
+      func_verbose "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+	# Preserve any variables that may affect compiler behavior
+	for var in $variables_saved_for_relink; do
+	  if eval test -z \"\${$var+set}\"; then
+	    relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	  elif eval var_value=\$$var; test -z "$var_value"; then
+	    relink_command="$var=; export $var; $relink_command"
+	  else
+	    func_quote_for_eval "$var_value"
+	    relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	  fi
+	done
+	relink_command="(cd `pwd`; $relink_command)"
+	relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if not in dry run mode.
+      $opt_dry_run || {
+	# win32 will think the script is a binary if it has
+	# a .exe suffix, so we strip it off here.
+	case $output in
+	  *.exe) func_stripname '' '.exe' "$output"
+	         output=$func_stripname_result ;;
+	esac
+	# test for cygwin because mv fails w/o .exe extensions
+	case $host in
+	  *cygwin*)
+	    exeext=.exe
+	    func_stripname '' '.exe' "$outputname"
+	    outputname=$func_stripname_result ;;
+	  *) exeext= ;;
+	esac
+	case $host in
+	  *cygwin* | *mingw* )
+	    func_dirname_and_basename "$output" "" "."
+	    output_name=$func_basename_result
+	    output_path=$func_dirname_result
+	    cwrappersource="$output_path/$objdir/lt-$output_name.c"
+	    cwrapper="$output_path/$output_name.exe"
+	    $RM $cwrappersource $cwrapper
+	    trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_cwrapperexe_src > $cwrappersource
+
+	    # The wrapper executable is built using the $host compiler,
+	    # because it contains $host paths and files. If cross-
+	    # compiling, it, like the target executable, must be
+	    # executed on the $host or under an emulation environment.
+	    $opt_dry_run || {
+	      $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+	      $STRIP $cwrapper
+	    }
+
+	    # Now, create the wrapper script for func_source use:
+	    func_ltwrapper_scriptname $cwrapper
+	    $RM $func_ltwrapper_scriptname_result
+	    trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+	    $opt_dry_run || {
+	      # note: this script will not be executed, so do not chmod.
+	      if test "x$build" = "x$host" ; then
+		$cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+	      else
+		func_emit_wrapper no > $func_ltwrapper_scriptname_result
+	      fi
+	    }
+	  ;;
+	  * )
+	    $RM $output
+	    trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_wrapper no > $output
+	    chmod +x $output
+	  ;;
+	esac
+      }
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      if test "$build_libtool_libs" = convenience; then
+	oldobjs="$libobjs_save $symfileobj"
+	addlibs="$convenience"
+	build_libtool_libs=no
+      else
+	if test "$build_libtool_libs" = module; then
+	  oldobjs="$libobjs_save"
+	  build_libtool_libs=no
+	else
+	  oldobjs="$old_deplibs $non_pic_objects"
+	  if test "$preload" = yes && test -f "$symfileobj"; then
+	    func_append oldobjs " $symfileobj"
+	  fi
+	fi
+	addlibs="$old_convenience"
+      fi
+
+      if test -n "$addlibs"; then
+	gentop="$output_objdir/${outputname}x"
+	func_append generated " $gentop"
+
+	func_extract_archives $gentop $addlibs
+	func_append oldobjs " $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+	cmds=$old_archive_from_new_cmds
+      else
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append oldobjs " $func_extract_archives_result"
+	fi
+
+	# POSIX demands no paths to be encoded in archives.  We have
+	# to avoid creating archives with duplicate basenames if we
+	# might have to extract them afterwards, e.g., when creating a
+	# static archive out of a convenience library, or when linking
+	# the entirety of a libtool archive into another (currently
+	# not supported by libtool).
+	if (for obj in $oldobjs
+	    do
+	      func_basename "$obj"
+	      $ECHO "$func_basename_result"
+	    done | sort | sort -uc >/dev/null 2>&1); then
+	  :
+	else
+	  echo "copying selected object files to avoid basename conflicts..."
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+	  func_mkdir_p "$gentop"
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  counter=1
+	  for obj in $save_oldobjs
+	  do
+	    func_basename "$obj"
+	    objbase="$func_basename_result"
+	    case " $oldobjs " in
+	    " ") oldobjs=$obj ;;
+	    *[\ /]"$objbase "*)
+	      while :; do
+		# Make sure we don't pick an alternate name that also
+		# overlaps.
+		newobj=lt$counter-$objbase
+		func_arith $counter + 1
+		counter=$func_arith_result
+		case " $oldobjs " in
+		*[\ /]"$newobj "*) ;;
+		*) if test ! -f "$gentop/$newobj"; then break; fi ;;
+		esac
+	      done
+	      func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+	      func_append oldobjs " $gentop/$newobj"
+	      ;;
+	    *) func_append oldobjs " $obj" ;;
+	    esac
+	  done
+	fi
+	func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+	tool_oldlib=$func_to_tool_file_result
+	eval cmds=\"$old_archive_cmds\"
+
+	func_len " $cmds"
+	len=$func_len_result
+	if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  cmds=$old_archive_cmds
+	elif test -n "$archiver_list_spec"; then
+	  func_verbose "using command file archive linking..."
+	  for obj in $oldobjs
+	  do
+	    func_to_tool_file "$obj"
+	    $ECHO "$func_to_tool_file_result"
+	  done > $output_objdir/$libname.libcmd
+	  func_to_tool_file "$output_objdir/$libname.libcmd"
+	  oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+	  cmds=$old_archive_cmds
+	else
+	  # the command line is too long to link in one step, link in parts
+	  func_verbose "using piecewise archive linking..."
+	  save_RANLIB=$RANLIB
+	  RANLIB=:
+	  objlist=
+	  concat_cmds=
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  # Is there a better way of finding the last object in the list?
+	  for obj in $save_oldobjs
+	  do
+	    last_oldobj=$obj
+	  done
+	  eval test_cmds=\"$old_archive_cmds\"
+	  func_len " $test_cmds"
+	  len0=$func_len_result
+	  len=$len0
+	  for obj in $save_oldobjs
+	  do
+	    func_len " $obj"
+	    func_arith $len + $func_len_result
+	    len=$func_arith_result
+	    func_append objlist " $obj"
+	    if test "$len" -lt "$max_cmd_len"; then
+	      :
+	    else
+	      # the above command should be used before it gets too long
+	      oldobjs=$objlist
+	      if test "$obj" = "$last_oldobj" ; then
+		RANLIB=$save_RANLIB
+	      fi
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+	      objlist=
+	      len=$len0
+	    fi
+	  done
+	  RANLIB=$save_RANLIB
+	  oldobjs=$objlist
+	  if test "X$oldobjs" = "X" ; then
+	    eval cmds=\"\$concat_cmds\"
+	  else
+	    eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+	  fi
+	fi
+      fi
+      func_execute_cmds "$cmds" 'exit $?'
+    done
+
+    test -n "$generated" && \
+      func_show_eval "${RM}r$generated"
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      func_verbose "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+	if eval test -z \"\${$var+set}\"; then
+	  relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	elif eval var_value=\$$var; test -z "$var_value"; then
+	  relink_command="$var=; export $var; $relink_command"
+	else
+	  func_quote_for_eval "$var_value"
+	  relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      if test "$hardcode_automatic" = yes ; then
+	relink_command=
+      fi
+
+      # Only create the output if not a dry run.
+      $opt_dry_run || {
+	for installed in no yes; do
+	  if test "$installed" = yes; then
+	    if test -z "$install_libdir"; then
+	      break
+	    fi
+	    output="$output_objdir/$outputname"i
+	    # Replace all uninstalled libtool libraries with the installed ones
+	    newdependency_libs=
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      *.la)
+		func_basename "$deplib"
+		name="$func_basename_result"
+		func_resolve_sysroot "$deplib"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$deplib' is not a valid libtool archive"
+		func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      -L*)
+		func_stripname -L '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -L$func_replace_sysroot_result"
+		;;
+	      -R*)
+		func_stripname -R '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -R$func_replace_sysroot_result"
+		;;
+	      *) func_append newdependency_libs " $deplib" ;;
+	      esac
+	    done
+	    dependency_libs="$newdependency_libs"
+	    newdlfiles=
+
+	    for lib in $dlfiles; do
+	      case $lib in
+	      *.la)
+	        func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      *) func_append newdlfiles " $lib" ;;
+	      esac
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+	      *.la)
+		# Only pass preopened files to the pseudo-archive (for
+		# eventual linking with the app. that links it) if we
+		# didn't already link the preopened objects directly into
+		# the library:
+		func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      esac
+	    done
+	    dlprefiles="$newdlprefiles"
+	  else
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlfiles " $abs"
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlprefiles " $abs"
+	    done
+	    dlprefiles="$newdlprefiles"
+	  fi
+	  $RM $output
+	  # place dlname in correct position for cygwin
+	  # In fact, it would be nice if we could use this code for all target
+	  # systems that can't hard-code library paths into their executables
+	  # and that have no shared library path variable independent of PATH,
+	  # but it turns out we can't easily determine that from inspecting
+	  # libtool variables, so we have to hard-code the OSs to which it
+	  # applies here; at the moment, that means platforms that use the PE
+	  # object format with DLL files.  See the long comment at the top of
+	  # tests/bindir.at for full details.
+	  tdlname=$dlname
+	  case $host,$output,$installed,$module,$dlname in
+	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+	      # If a -bindir argument was supplied, place the dll there.
+	      if test "x$bindir" != x ;
+	      then
+		func_relative_path "$install_libdir" "$bindir"
+		tdlname=$func_relative_path_result$dlname
+	      else
+		# Otherwise fall back on heuristic.
+		tdlname=../bin/$dlname
+	      fi
+	      ;;
+	  esac
+	  $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+	  if test "$installed" = no && test "$need_relink" = yes; then
+	    $ECHO >> $output "\
+relink_command=\"$relink_command\""
+	  fi
+	done
+      }
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+}
+
+{ test "$opt_mode" = link || test "$opt_mode" = relink; } &&
+    func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+    $opt_debug
+    RM="$nonopt"
+    files=
+    rmforce=
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    for arg
+    do
+      case $arg in
+      -f) func_append RM " $arg"; rmforce=yes ;;
+      -*) func_append RM " $arg" ;;
+      *) func_append files " $arg" ;;
+      esac
+    done
+
+    test -z "$RM" && \
+      func_fatal_help "you must specify an RM program"
+
+    rmdirs=
+
+    for file in $files; do
+      func_dirname "$file" "" "."
+      dir="$func_dirname_result"
+      if test "X$dir" = X.; then
+	odir="$objdir"
+      else
+	odir="$dir/$objdir"
+      fi
+      func_basename "$file"
+      name="$func_basename_result"
+      test "$opt_mode" = uninstall && odir="$dir"
+
+      # Remember odir for removal later, being careful to avoid duplicates
+      if test "$opt_mode" = clean; then
+	case " $rmdirs " in
+	  *" $odir "*) ;;
+	  *) func_append rmdirs " $odir" ;;
+	esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if { test -L "$file"; } >/dev/null 2>&1 ||
+	 { test -h "$file"; } >/dev/null 2>&1 ||
+	 test -f "$file"; then
+	:
+      elif test -d "$file"; then
+	exit_status=1
+	continue
+      elif test "$rmforce" = yes; then
+	continue
+      fi
+
+      rmfiles="$file"
+
+      case $name in
+      *.la)
+	# Possibly a libtool archive, so verify it.
+	if func_lalib_p "$file"; then
+	  func_source $dir/$name
+
+	  # Delete the libtool libraries and symlinks.
+	  for n in $library_names; do
+	    func_append rmfiles " $odir/$n"
+	  done
+	  test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+	  case "$opt_mode" in
+	  clean)
+	    case " $library_names " in
+	    *" $dlname "*) ;;
+	    *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+	    esac
+	    test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+	    ;;
+	  uninstall)
+	    if test -n "$library_names"; then
+	      # Do each command in the postuninstall commands.
+	      func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+
+	    if test -n "$old_library"; then
+	      # Do each command in the old_postuninstall commands.
+	      func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+	    # FIXME: should reinstall the best remaining shared library.
+	    ;;
+	  esac
+	fi
+	;;
+
+      *.lo)
+	# Possibly a libtool object, so verify it.
+	if func_lalib_p "$file"; then
+
+	  # Read the .lo file
+	  func_source $dir/$name
+
+	  # Add PIC object to the list of files to remove.
+	  if test -n "$pic_object" &&
+	     test "$pic_object" != none; then
+	    func_append rmfiles " $dir/$pic_object"
+	  fi
+
+	  # Add non-PIC object to the list of files to remove.
+	  if test -n "$non_pic_object" &&
+	     test "$non_pic_object" != none; then
+	    func_append rmfiles " $dir/$non_pic_object"
+	  fi
+	fi
+	;;
+
+      *)
+	if test "$opt_mode" = clean ; then
+	  noexename=$name
+	  case $file in
+	  *.exe)
+	    func_stripname '' '.exe' "$file"
+	    file=$func_stripname_result
+	    func_stripname '' '.exe' "$name"
+	    noexename=$func_stripname_result
+	    # $file with .exe has already been added to rmfiles,
+	    # add $file without .exe
+	    func_append rmfiles " $file"
+	    ;;
+	  esac
+	  # Do a test to see if this is a libtool program.
+	  if func_ltwrapper_p "$file"; then
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      relink_command=
+	      func_source $func_ltwrapper_scriptname_result
+	      func_append rmfiles " $func_ltwrapper_scriptname_result"
+	    else
+	      relink_command=
+	      func_source $dir/$noexename
+	    fi
+
+	    # note $name still contains .exe if it was in $file originally
+	    # as does the version of $file that was added into $rmfiles
+	    func_append rmfiles " $odir/$name $odir/${name}S.${objext}"
+	    if test "$fast_install" = yes && test -n "$relink_command"; then
+	      func_append rmfiles " $odir/lt-$name"
+	    fi
+	    if test "X$noexename" != "X$name" ; then
+	      func_append rmfiles " $odir/lt-${noexename}.c"
+	    fi
+	  fi
+	fi
+	;;
+      esac
+      func_show_eval "$RM $rmfiles" 'exit_status=1'
+    done
+
+    # Try to remove the ${objdir}s in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+	func_show_eval "rmdir $dir >/dev/null 2>&1"
+      fi
+    done
+
+    exit $exit_status
+}
+
+{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } &&
+    func_mode_uninstall ${1+"$@"}
+
+test -z "$opt_mode" && {
+  help="$generic_help"
+  func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+  func_fatal_help "invalid operation mode \`$opt_mode'"
+
+if test -n "$exec_cmd"; then
+  eval exec "$exec_cmd"
+  exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+

+ 106 - 0
compat/libusb-1.0/msvc/ddk_build.cmd

@@ -0,0 +1,106 @@
+@rem default builds static library.
+@rem you can pass the following arguments (case insensitive):
+@rem - "DLL" to build a DLL instead of a static library
+@rem - "/MT" to build a static library compatible with MSVC's /MT option (LIBCMT vs MSVCRT)
+@echo off
+
+if Test%BUILD_ALT_DIR%==Test goto usage
+
+rem process commandline parameters
+set TARGET=LIBRARY
+set STATIC_LIBC=
+set version=1.0
+
+if "%1" == "" goto no_more_args
+rem /I for case insensitive
+if /I Test%1==TestDLL set TARGET=DYNLINK
+if /I Test%1==Test/MT set STATIC_LIBC=1
+:no_more_args
+
+cd ..\libusb\os
+echo TARGETTYPE=%TARGET% > target
+copy target+..\..\msvc\libusb_sources sources >NUL 2>&1
+del target
+@echo on
+build -cwgZ
+@echo off
+if errorlevel 1 goto builderror
+cd ..\..
+
+set cpudir=i386
+set destType=Win32
+if %_BUILDARCH%==x86 goto isI386
+set cpudir=amd64
+set destType=x64
+:isI386
+
+set srcPath=libusb\os\obj%BUILD_ALT_DIR%\%cpudir%
+
+set dstPath=%destType%\Debug
+if %DDKBUILDENV%==chk goto isDebug
+set dstPath=%destType%\Release
+:isDebug
+
+if exist %destType% goto md2
+mkdir %destType%
+:md2
+if exist %dstPath% goto md3
+mkdir %dstPath%
+:md3
+if exist %dstPath%\dll goto md4
+mkdir %dstPath%\dll
+:md4
+if exist %dstPath%\lib goto md5
+md %dstPath%\lib
+:md5
+if exist %dstPath%\examples goto md6
+md %dstPath%\examples
+:md6
+@echo on
+
+@if /I NOT Test%1==TestDLL goto copylib
+copy %srcPath%\libusb-%version%.dll %dstPath%\dll
+copy %srcPath%\libusb-%version%.pdb %dstPath%\dll
+:copylib
+copy %srcPath%\libusb-%version%.lib %dstPath%\lib
+
+@echo off
+
+if exist examples\listdevs_ddkbuild goto md7
+md examples\listdevs_ddkbuild
+:md7
+
+cd examples\listdevs_ddkbuild
+copy ..\..\msvc\listdevs_sources sources >NUL 2>&1
+@echo on
+build -cwgZ
+@echo off
+if errorlevel 1 goto buildlistdevserror
+cd ..\..
+
+set srcPath=examples\listdevs_ddkbuild\obj%BUILD_ALT_DIR%\%cpudir%
+@echo on
+
+copy %srcPath%\listdevs.exe %dstPath%\examples
+copy %srcPath%\listdevs.pdb %dstPath%\examples
+
+cd msvc
+goto done
+
+
+:builderror
+cd ..\..\msvc
+echo Build failed
+goto done
+
+:buildlistdevserror
+cd ..\..\msvc
+echo listdevs build failed
+goto done
+
+:usage
+echo ddk_build must be run in a WDK build environment
+pause
+goto done
+
+:done

+ 142 - 0
compat/libusb-1.0/msvc/ddk_build.cmd.orig

@@ -0,0 +1,142 @@
+@rem default builds static library.
+@rem you can pass the following arguments (case insensitive):
+@rem - "DLL" to build a DLL instead of a static library
+@rem - "/MT" to build a static library compatible with MSVC's /MT option (LIBCMT vs MSVCRT)
+@echo off
+
+if Test%BUILD_ALT_DIR%==Test goto usage
+
+rem process commandline parameters
+set TARGET=LIBRARY
+set STATIC_LIBC=
+set version=1.0
+
+if "%1" == "" goto no_more_args
+rem /I for case insensitive
+if /I Test%1==TestDLL set TARGET=DYNLINK
+if /I Test%1==Test/MT set STATIC_LIBC=1
+:no_more_args
+
+cd ..\libusb\os
+echo TARGETTYPE=%TARGET% > target
+copy target+..\..\msvc\libusb_sources sources >NUL 2>&1
+del target
+@echo on
+build -cwgZ
+@echo off
+if errorlevel 1 goto builderror
+cd ..\..
+
+set cpudir=i386
+set destType=Win32
+if %_BUILDARCH%==x86 goto isI386
+set cpudir=amd64
+set destType=x64
+:isI386
+
+set srcPath=libusb\os\obj%BUILD_ALT_DIR%\%cpudir%
+
+set dstPath=%destType%\Debug
+if %DDKBUILDENV%==chk goto isDebug
+set dstPath=%destType%\Release
+:isDebug
+
+if exist %destType% goto md2
+mkdir %destType%
+:md2
+if exist %dstPath% goto md3
+mkdir %dstPath%
+:md3
+if exist %dstPath%\dll goto md4
+mkdir %dstPath%\dll
+:md4
+if exist %dstPath%\lib goto md5
+md %dstPath%\lib
+:md5
+if exist %dstPath%\examples goto md6
+md %dstPath%\examples
+:md6
+@echo on
+
+@if /I NOT Test%1==TestDLL goto copylib
+copy %srcPath%\libusb-%version%.dll %dstPath%\dll
+copy %srcPath%\libusb-%version%.pdb %dstPath%\dll
+:copylib
+copy %srcPath%\libusb-%version%.lib %dstPath%\lib
+
+@echo off
+
+if exist examples\listdevs_ddkbuild goto md7
+md examples\listdevs_ddkbuild
+:md7
+
+cd examples\listdevs_ddkbuild
+copy ..\..\msvc\listdevs_sources sources >NUL 2>&1
+@echo on
+build -cwgZ
+@echo off
+if errorlevel 1 goto buildlistdevserror
+cd ..\..
+
+set srcPath=examples\listdevs_ddkbuild\obj%BUILD_ALT_DIR%\%cpudir%
+@echo on
+
+copy %srcPath%\listdevs.exe %dstPath%\examples
+copy %srcPath%\listdevs.pdb %dstPath%\examples
+
+cd msvc
+goto done
+
+
+:builderror
+cd ..\..\msvc
+echo Build failed
+goto done
+
+<<<<<<< HEAD
+:buildlistdevserror
+cd ..\..\msvc
+echo listdevs build failed
+=======
+if exist examples\getopt\getopt_ddkbuild goto md9
+md examples\getopt\getopt_ddkbuild
+:md9
+
+cd examples\getopt\getopt_ddkbuild
+copy ..\..\..\msvc\getopt_sources sources >NUL 2>&1
+@echo on
+%BUILD_CMD%
+@echo off
+if errorlevel 1 goto builderror
+cd ..\..\..
+
+if exist examples\fxload_ddkbuild goto md8
+md examples\fxload_ddkbuild
+:md8
+
+cd examples\fxload_ddkbuild
+copy ..\..\msvc\fxload_sources sources >NUL 2>&1
+@echo on
+%BUILD_CMD%
+@echo off
+if errorlevel 1 goto builderror
+cd ..\..
+
+set srcPath=examples\fxload_ddkbuild\obj%BUILD_ALT_DIR%\%cpudir%
+@echo on
+
+copy %srcPath%\fxload.exe %dstPath%\examples
+copy %srcPath%\fxload.pdb %dstPath%\examples
+
+@echo off
+
+cd msvc
+>>>>>>> 0597533... Samples: Add fxload sample for Cypress EZ-USB chips
+goto done
+
+:usage
+echo ddk_build must be run in a WDK build environment
+pause
+goto done
+
+:done

+ 56 - 0
compat/libusb-1.0/msvc/libusb.dsw

@@ -0,0 +1,56 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "libusb_dll"=".\libusb_dll.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libusb_static"=".\libusb_static.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "listdevs"=".\listdevs.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libusb_static
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+

+ 190 - 0
compat/libusb-1.0/msvc/libusb_dll.dsp

@@ -0,0 +1,190 @@
+# Microsoft Developer Studio Project File - Name="libusb_dll" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libusb_dll - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "libusb_dll.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "libusb_dll.mak" CFG="libusb_dll - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "libusb_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libusb_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "libusb_dll - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "../Win32/Release/dll"
+# PROP Intermediate_Dir "../Win32/Release/dll"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "LIBUSB_DLL_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../libusb" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /U "_MBCS" /D "_USRDLL" /FR /FD /EHsc /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Win32/Release/dll/libusb-1.0.dll"
+
+!ELSEIF  "$(CFG)" == "libusb_dll - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "../Win32/Debug/dll"
+# PROP Intermediate_Dir "../Win32/Debug/dll"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "LIBUSB_DLL_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "../libusb" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /U "_MBCS" /D "_USRDLL" /FR /FD /EHsc /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /n
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Win32/Debug/dll/libusb-1.0.dll"
+# SUBTRACT LINK32 /pdb:none /incremental:no
+
+!ENDIF 
+
+# Begin Target
+
+# Name "libusb_dll - Win32 Release"
+# Name "libusb_dll - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\libusb\core.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\darwin_usb.c
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\descriptor.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\io.c
+# End Source File
+# Begin Source File
+
+SOURCE="..\libusb\libusb-1.0.rc"
+# End Source File
+# Begin Source File
+
+SOURCE="..\libusb\libusb-1.0.def"
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\linux_usbfs.c
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\poll_windows.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\sync.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\threads_windows.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\windows_usb.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\config.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\darwin_usb.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\libusb.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\libusbi.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\linux_usbfs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\poll_posix.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\poll_windows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\threads_posix.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\threads_windows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\windows_usb.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project

+ 421 - 0
compat/libusb-1.0/msvc/libusb_dll.vcproj

@@ -0,0 +1,421 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="libusb-1.0 (dll)"
+	ProjectGUID="{8224C054-5968-4238-832C-167155E7ECC3}"
+	RootNamespace="libusbdll"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="..\$(PlatformName)\$(ConfigurationName)\dll"
+			IntermediateDirectory="..\$(PlatformName)\$(ConfigurationName)\dll\libusb-1.0"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories=".;..\libusb"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)\libusb-1.0.dll"
+				LinkIncremental="2"
+				ModuleDefinitionFile="..\libusb\libusb-1.0.def"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="..\$(PlatformName)\$(ConfigurationName)\dll"
+			IntermediateDirectory="..\$(PlatformName)\$(ConfigurationName)\dll\libusb-1.0"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories=".;..\libusb"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)\libusb-1.0.dll"
+				LinkIncremental="1"
+				ModuleDefinitionFile="..\libusb\libusb-1.0.def"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="..\$(PlatformName)\$(ConfigurationName)\dll"
+			IntermediateDirectory="..\$(PlatformName)\$(ConfigurationName)\dll\libusb-1.0"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories=".;..\libusb"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)\libusb-1.0.dll"
+				LinkIncremental="2"
+				ModuleDefinitionFile="..\libusb\libusb-1.0.def"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="..\$(PlatformName)\$(ConfigurationName)\dll"
+			IntermediateDirectory="..\$(PlatformName)\$(ConfigurationName)\dll\libusb-1.0"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories=".;..\libusb"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)\libusb-1.0.dll"
+				LinkIncremental="1"
+				ModuleDefinitionFile="..\libusb\libusb-1.0.def"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\libusb\core.c"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\descriptor.c"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\io.c"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\libusb-1.0.def"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\sync.c"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\os\threads_windows.c"
+				>
+			</File>
+
+			<File
+				RelativePath="..\libusb\os\poll_windows.c"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\os\windows_usb.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\config.h"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\libusb.h"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\libusbi.h"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\os\threads_windows.h"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\os\poll_windows.h"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\os\windows_usb.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+			<File
+				RelativePath="..\libusb\libusb-1.0.rc"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

+ 166 - 0
compat/libusb-1.0/msvc/libusb_dll.vcxproj

@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectName>libusb-1.0 (dll)</ProjectName>
+    <ProjectGuid>{349EE8FA-7D25-4909-AAF5-FF3FADE72187}</ProjectGuid>
+    <RootNamespace>libusbdll</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)..\$(Platform)\$(Configuration)\dll\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-1.0\</IntDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\$(Platform)\$(Configuration)\dll\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-1.0\</IntDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)..\$(Platform)\$(Configuration)\dll\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-1.0\</IntDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)..\$(Platform)\$(Configuration)\dll\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-1.0\</IntDir>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">libusb-1.0</TargetName>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">libusb-1.0</TargetName>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">libusb-1.0</TargetName>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">libusb-1.0</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <OutputFile>$(OutDir)libusb-1.0.dll</OutputFile>
+      <ModuleDefinitionFile>..\libusb\libusb-1.0.def</ModuleDefinitionFile>
+      <EmbedManagedResourceFile>libusb-1.0.rc;%(EmbedManagedResourceFile)</EmbedManagedResourceFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Midl>
+      <TargetEnvironment>X64</TargetEnvironment>
+    </Midl>
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_WIN32;_WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <OutputFile>$(OutDir)libusb-1.0.dll</OutputFile>
+      <ModuleDefinitionFile>..\libusb\libusb-1.0.def</ModuleDefinitionFile>
+      <EmbedManagedResourceFile>libusb-1.0.rc;%(EmbedManagedResourceFile)</EmbedManagedResourceFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_WIN32;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+    </ClCompile>
+    <Link>
+      <OutputFile>$(OutDir)libusb-1.0.dll</OutputFile>
+      <ModuleDefinitionFile>..\libusb\libusb-1.0.def</ModuleDefinitionFile>
+      <EmbedManagedResourceFile>libusb-1.0.rc;%(EmbedManagedResourceFile)</EmbedManagedResourceFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Midl>
+      <TargetEnvironment>X64</TargetEnvironment>
+    </Midl>
+    <ClCompile>
+      <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_WIN32;_WIN64;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+    </ClCompile>
+    <Link>
+      <OutputFile>$(OutDir)libusb-1.0.dll</OutputFile>
+      <ModuleDefinitionFile>..\libusb\libusb-1.0.def</ModuleDefinitionFile>
+      <EmbedManagedResourceFile>libusb-1.0.rc;%(EmbedManagedResourceFile)</EmbedManagedResourceFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\libusb\core.c" />
+    <ClCompile Include="..\libusb\descriptor.c" />
+    <ClCompile Include="..\libusb\io.c" />
+    <ClCompile Include="..\libusb\os\poll_windows.c" />
+    <ClCompile Include="..\libusb\sync.c" />
+    <ClCompile Include="..\libusb\os\threads_windows.c" />
+    <ClCompile Include="..\libusb\os\windows_usb.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include=".\config.h" />
+    <ClInclude Include="..\libusb\libusb.h" />
+    <ClInclude Include="..\libusb\libusbi.h" />
+    <ClInclude Include="..\libusb\os\poll_windows.h" />
+    <ClInclude Include="..\libusb\os\threads_windows.h" />
+    <ClInclude Include="..\libusb\os\windows_usb.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\libusb\libusb-1.0.def" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="..\libusb\libusb-1.0.rc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 69 - 0
compat/libusb-1.0/msvc/libusb_dll.vcxproj.filters

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{d81e81ca-b13e-4a15-b54b-b12b41361e6b}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\libusb\core.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\libusb\descriptor.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\libusb\io.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\libusb\os\poll_windows.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\libusb\sync.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\libusb\os\threads_windows.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\libusb\os\windows_usb.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include=".\config.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\libusb\libusb.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\libusb\libusbi.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\libusb\os\poll_windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\libusb\os\threads_windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\libusb\os\windows_usb.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\libusb\libusb-1.0.def">
+      <Filter>Resource Files</Filter>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="..\libusb\libusb-1.0.rc">
+      <Filter>Resource Files</Filter>
+    </ResourceCompile>
+  </ItemGroup>
+</Project>

+ 36 - 0
compat/libusb-1.0/msvc/libusb_sources

@@ -0,0 +1,36 @@
+#TARGETTYPE is not defined, to allow selection between static lib or DLL with ddk_build
+TARGETNAME=libusb-1.0
+DLLDEF=..\libusb-1.0.def
+
+!IFNDEF MSC_WARNING_LEVEL
+MSC_WARNING_LEVEL=/W3
+!ENDIF
+
+!IFDEF STATIC_LIBC
+USE_LIBCMT=1
+!ELSE
+USE_MSVCRT=1
+!ENDIF
+
+INCLUDES=..;..\..\msvc;$(DDK_INC_PATH)
+C_DEFINES= $(C_DEFINES) $(LIBUSB_DEFINES) /DDDKBUILD
+
+# http://jpassing.com/2009/10/21/ltcg-issues-with-the-win7amd64-environment-of-wdk-7600/
+# prevents the following error when using the 64 bit static lib with Visual Studio 2010:
+# "fatal error C1001: An internal error has occurred in the compiler.
+# (compiler file 'f:\dd\vctools\compiler\utc\src\p2\p2symtab.c', line 1823)"
+# and the following with Visual Studio 2010:
+# "fatal error C1047: The object or library file 'libusb-1.0.lib' was created with
+#  an older compiler than other objects; rebuild old objects and libraries"
+USER_C_FLAGS=/GL-
+
+TARGETLIBS=$(SDK_LIB_PATH)\kernel32.lib
+
+SOURCES=..\core.c \
+	..\descriptor.c \
+	..\io.c \
+	..\sync.c \
+	threads_windows.c \
+	poll_windows.c \
+	windows_usb.c \
+	..\libusb-1.0.rc

+ 170 - 0
compat/libusb-1.0/msvc/libusb_static.dsp

@@ -0,0 +1,170 @@
+# Microsoft Developer Studio Project File - Name="libusb_static" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libusb_static - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "libusb_static.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "libusb_static.mak" CFG="libusb_static - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "libusb_static - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libusb_static - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "libusb_static - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "../Win32/Release/lib"
+# PROP Intermediate_Dir "../Win32/Release/lib"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../libusb" /D "WIN32" /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /U "_MBCS" /D "_LIB" /FR /FD /EHsc /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"../Win32/Release/lib/libusb-1.0.lib"
+
+!ELSEIF  "$(CFG)" == "libusb_static - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "../Win32/Debug/lib"
+# PROP Intermediate_Dir "../Win32/Debug/lib"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "../libusb" /D "WIN32" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /U "_MBCS" /D "_LIB" /FR /FD /GZ /EHsc /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /n
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"../Win32/Debug/lib/libusb-1.0.lib"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "libusb_static - Win32 Release"
+# Name "libusb_static - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\libusb\core.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\darwin_usb.c
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\descriptor.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\io.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\linux_usbfs.c
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\poll_windows.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\sync.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\threads_windows.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\windows_usb.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\config.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\darwin_usb.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\libusb.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\libusbi.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\linux_usbfs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\poll_posix.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\poll_windows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\threads_posix.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\threads_windows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\libusb\os\windows_usb.h
+# End Source File
+# End Group
+# End Target
+# End Project

+ 346 - 0
compat/libusb-1.0/msvc/libusb_static.vcproj

@@ -0,0 +1,346 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="libusb-1.0 (static)"
+	ProjectGUID="{5AB6B770-1925-48D5-ABC2-930F3259C020}"
+	RootNamespace="libusb"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="..\$(PlatformName)\$(ConfigurationName)\lib"
+			IntermediateDirectory="..\$(PlatformName)\$(ConfigurationName)\lib\libusb-1.0"
+			ConfigurationType="4"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories=".;..\libusb"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="$(OutDir)\libusb-1.0.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="..\$(PlatformName)\$(ConfigurationName)\lib"
+			IntermediateDirectory="..\$(PlatformName)\$(ConfigurationName)\lib\libusb-1.0"
+			ConfigurationType="4"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories=".;..\libusb"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="$(OutDir)\libusb-1.0.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="..\$(PlatformName)\$(ConfigurationName)\lib"
+			IntermediateDirectory="..\$(PlatformName)\$(ConfigurationName)\lib\libusb-1.0"
+			ConfigurationType="4"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories=".;..\libusb"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="$(OutDir)\libusb-1.0.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="..\$(PlatformName)\$(ConfigurationName)\lib"
+			IntermediateDirectory="..\$(PlatformName)\$(ConfigurationName)\lib\libusb-1.0"
+			ConfigurationType="4"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories=".;..\libusb"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="$(OutDir)\libusb-1.0.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\libusb\core.c"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\descriptor.c"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\io.c"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\sync.c"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\os\threads_windows.c"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\os\poll_windows.c"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\os\windows_usb.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\config.h"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\libusb.h"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\libusbi.h"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\os\threads_windows.h"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\os\poll_windows.h"
+				>
+			</File>
+			<File
+				RelativePath="..\libusb\os\windows_usb.h"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

+ 150 - 0
compat/libusb-1.0/msvc/libusb_static.vcxproj

@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectName>libusb-1.0 (static)</ProjectName>
+    <ProjectGuid>{349EE8F9-7D25-4909-AAF5-FF3FADE72187}</ProjectGuid>
+    <RootNamespace>libusb</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)..\$(Platform)\$(Configuration)\lib\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-1.0\</IntDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\$(Platform)\$(Configuration)\lib\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-1.0\</IntDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)..\$(Platform)\$(Configuration)\lib\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-1.0\</IntDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)..\$(Platform)\$(Configuration)\lib\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)..\$(Platform)\$(Configuration)\lib\libusb-1.0\</IntDir>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">libusb-1.0</TargetName>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">libusb-1.0</TargetName>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">libusb-1.0</TargetName>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">libusb-1.0</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Lib>
+      <OutputFile>$(OutDir)libusb-1.0.lib</OutputFile>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Midl>
+      <TargetEnvironment>X64</TargetEnvironment>
+    </Midl>
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_WIN32;_WIN64;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Lib>
+      <OutputFile>$(OutDir)libusb-1.0.lib</OutputFile>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_WIN32;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+    </ClCompile>
+    <Lib>
+      <OutputFile>$(OutDir)libusb-1.0.lib</OutputFile>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Midl>
+      <TargetEnvironment>X64</TargetEnvironment>
+    </Midl>
+    <ClCompile>
+      <AdditionalIncludeDirectories>.;..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_WIN32;_WIN64;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+    </ClCompile>
+    <Lib>
+      <OutputFile>$(OutDir)libusb-1.0.lib</OutputFile>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\libusb\core.c" />
+    <ClCompile Include="..\libusb\descriptor.c" />
+    <ClCompile Include="..\libusb\io.c" />
+    <ClCompile Include="..\libusb\os\poll_windows.c" />
+    <ClCompile Include="..\libusb\sync.c" />
+    <ClCompile Include="..\libusb\os\threads_windows.c" />
+    <ClCompile Include="..\libusb\os\windows_usb.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include=".\config.h" />
+    <ClInclude Include="..\libusb\libusb.h" />
+    <ClInclude Include="..\libusb\libusbi.h" />
+    <ClInclude Include="..\libusb\os\poll_windows.h" />
+    <ClInclude Include="..\libusb\os\threads_windows.h" />
+    <ClInclude Include="..\libusb\os\windows_usb.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 56 - 0
compat/libusb-1.0/msvc/libusb_static.vcxproj.filters

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\libusb\core.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\libusb\descriptor.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\libusb\io.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\libusb\os\poll_windows.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\libusb\sync.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\libusb\os\threads_windows.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\libusb\os\windows_usb.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include=".\config.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\libusb\libusb.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\libusb\libusbi.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\libusb\os\poll_windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\libusb\os\threads_windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\libusb\os\windows_usb.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>

+ 61 - 0
compat/libusb-1.0/msvc/libusb_vs2005.sln

@@ -0,0 +1,61 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "libusb_static.vcproj", "{5AB6B770-1925-48D5-ABC2-930F3259C020}"
+	ProjectSection(WebsiteProperties) = preProject
+		Debug.AspNetCompiler.Debug = "True"
+		Release.AspNetCompiler.Debug = "False"
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (dll)", "libusb_dll.vcproj", "{8224C054-5968-4238-832C-167155E7ECC3}"
+	ProjectSection(WebsiteProperties) = preProject
+		Debug.AspNetCompiler.Debug = "True"
+		Release.AspNetCompiler.Debug = "False"
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "listdevs", "listdevs.vcproj", "{98CFD8FA-EE20-40D5-AF13-F8C4856D6CA5}"
+	ProjectSection(WebsiteProperties) = preProject
+		Debug.AspNetCompiler.Debug = "True"
+		Release.AspNetCompiler.Debug = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{5AB6B770-1925-48D5-ABC2-930F3259C020} = {5AB6B770-1925-48D5-ABC2-930F3259C020}
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Debug|x64 = Debug|x64
+		Release|Win32 = Release|Win32
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{5AB6B770-1925-48D5-ABC2-930F3259C020}.Debug|Win32.ActiveCfg = Debug|Win32
+		{5AB6B770-1925-48D5-ABC2-930F3259C020}.Debug|Win32.Build.0 = Debug|Win32
+		{5AB6B770-1925-48D5-ABC2-930F3259C020}.Debug|x64.ActiveCfg = Debug|x64
+		{5AB6B770-1925-48D5-ABC2-930F3259C020}.Debug|x64.Build.0 = Debug|x64
+		{5AB6B770-1925-48D5-ABC2-930F3259C020}.Release|Win32.ActiveCfg = Release|Win32
+		{5AB6B770-1925-48D5-ABC2-930F3259C020}.Release|Win32.Build.0 = Release|Win32
+		{5AB6B770-1925-48D5-ABC2-930F3259C020}.Release|x64.ActiveCfg = Release|x64
+		{5AB6B770-1925-48D5-ABC2-930F3259C020}.Release|x64.Build.0 = Release|x64
+		{8224C054-5968-4238-832C-167155E7ECC3}.Debug|Win32.ActiveCfg = Debug|Win32
+		{8224C054-5968-4238-832C-167155E7ECC3}.Debug|Win32.Build.0 = Debug|Win32
+		{8224C054-5968-4238-832C-167155E7ECC3}.Debug|x64.ActiveCfg = Debug|x64
+		{8224C054-5968-4238-832C-167155E7ECC3}.Debug|x64.Build.0 = Debug|x64
+		{8224C054-5968-4238-832C-167155E7ECC3}.Release|Win32.ActiveCfg = Release|Win32
+		{8224C054-5968-4238-832C-167155E7ECC3}.Release|Win32.Build.0 = Release|Win32
+		{8224C054-5968-4238-832C-167155E7ECC3}.Release|x64.ActiveCfg = Release|x64
+		{8224C054-5968-4238-832C-167155E7ECC3}.Release|x64.Build.0 = Release|x64
+		{98CFD8FA-EE20-40D5-AF13-F8C4856D6CA5}.Debug|Win32.ActiveCfg = Debug|Win32
+		{98CFD8FA-EE20-40D5-AF13-F8C4856D6CA5}.Debug|Win32.Build.0 = Debug|Win32
+		{98CFD8FA-EE20-40D5-AF13-F8C4856D6CA5}.Debug|x64.ActiveCfg = Debug|x64
+		{98CFD8FA-EE20-40D5-AF13-F8C4856D6CA5}.Debug|x64.Build.0 = Debug|x64
+		{98CFD8FA-EE20-40D5-AF13-F8C4856D6CA5}.Release|Win32.ActiveCfg = Release|Win32
+		{98CFD8FA-EE20-40D5-AF13-F8C4856D6CA5}.Release|Win32.Build.0 = Release|Win32
+		{98CFD8FA-EE20-40D5-AF13-F8C4856D6CA5}.Release|x64.ActiveCfg = Release|x64
+		{98CFD8FA-EE20-40D5-AF13-F8C4856D6CA5}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 49 - 0
compat/libusb-1.0/msvc/libusb_vs2010.sln

@@ -0,0 +1,49 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "libusb_static.vcxproj", "{349EE8F9-7D25-4909-AAF5-FF3FADE72187}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (dll)", "libusb_dll.vcxproj", "{349EE8FA-7D25-4909-AAF5-FF3FADE72187}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "listdevs", "listdevs.vcxproj", "{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Debug|x64 = Debug|x64
+		Release|Win32 = Release|Win32
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.ActiveCfg = Debug|Win32
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.Build.0 = Debug|Win32
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.ActiveCfg = Release|Win32
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.Build.0 = Release|Win32
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64
+		{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.ActiveCfg = Debug|Win32
+		{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64
+		{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.ActiveCfg = Release|Win32
+		{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|Win32.Build.0 = Debug|Win32
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|x64.ActiveCfg = Debug|x64
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|x64.Build.0 = Debug|x64
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|Win32.ActiveCfg = Release|Win32
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|Win32.Build.0 = Release|Win32
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|x64.ActiveCfg = Release|x64
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|x64.Build.0 = Release|x64
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|Win32.ActiveCfg = Debug|Win32
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|Win32.Build.0 = Debug|Win32
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|x64.ActiveCfg = Debug|x64
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|x64.Build.0 = Debug|x64
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|Win32.ActiveCfg = Release|Win32
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|Win32.Build.0 = Release|Win32
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|x64.ActiveCfg = Release|x64
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 77 - 0
compat/libusb-1.0/msvc/libusb_vs2010.sln.orig

@@ -0,0 +1,77 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "libusb_static.vcxproj", "{349EE8F9-7D25-4909-AAF5-FF3FADE72187}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (dll)", "libusb_dll.vcxproj", "{349EE8FA-7D25-4909-AAF5-FF3FADE72187}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "listdevs", "listdevs.vcxproj", "{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}"
+EndProject
+<<<<<<< HEAD:msvc/libusb_vs2010.sln
+=======
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xusb", "xusb.vcxproj", "{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fxload", "fxload.vcxproj", "{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}"
+	ProjectSection(ProjectDependencies) = postProject
+		{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E} = {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt", "getopt.vcxproj", "{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}"
+EndProject
+>>>>>>> 0597533... Samples: Add fxload sample for Cypress EZ-USB chips:msvc/libusb_2010.sln
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Debug|x64 = Debug|x64
+		Release|Win32 = Release|Win32
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.ActiveCfg = Debug|Win32
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.Build.0 = Debug|Win32
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.ActiveCfg = Release|Win32
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.Build.0 = Release|Win32
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64
+		{349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64
+		{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.ActiveCfg = Debug|Win32
+		{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64
+		{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.ActiveCfg = Release|Win32
+		{349EE8FA-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|Win32.Build.0 = Debug|Win32
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|x64.ActiveCfg = Debug|x64
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Debug|x64.Build.0 = Debug|x64
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|Win32.ActiveCfg = Release|Win32
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|Win32.Build.0 = Release|Win32
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|x64.ActiveCfg = Release|x64
+		{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}.Release|x64.Build.0 = Release|x64
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|Win32.ActiveCfg = Debug|Win32
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|Win32.Build.0 = Debug|Win32
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|x64.ActiveCfg = Debug|x64
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Debug|x64.Build.0 = Debug|x64
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|Win32.ActiveCfg = Release|Win32
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|Win32.Build.0 = Release|Win32
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|x64.ActiveCfg = Release|x64
+		{3F3138D0-7AB7-4268-9BF3-1A3EA5503A11}.Release|x64.Build.0 = Release|x64
+		{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|Win32.ActiveCfg = Debug|Win32
+		{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|Win32.Build.0 = Debug|Win32
+		{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|x64.ActiveCfg = Debug|x64
+		{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Debug|x64.Build.0 = Debug|x64
+		{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|Win32.ActiveCfg = Release|Win32
+		{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|Win32.Build.0 = Release|Win32
+		{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|x64.ActiveCfg = Release|x64
+		{9E166F7A-A793-9FB6-0A67-F0AED8AE8C88}.Release|x64.Build.0 = Release|x64
+		{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|Win32.ActiveCfg = Debug|Win32
+		{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|Win32.Build.0 = Debug|Win32
+		{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.ActiveCfg = Debug|x64
+		{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.Build.0 = Debug|x64
+		{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|Win32.ActiveCfg = Release|Win32
+		{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|Win32.Build.0 = Release|Win32
+		{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.ActiveCfg = Release|x64
+		{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 103 - 0
compat/libusb-1.0/msvc/listdevs.dsp

@@ -0,0 +1,103 @@
+# Microsoft Developer Studio Project File - Name="listdevs" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=listdevs - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "listdevs.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "listdevs.mak" CFG="listdevs - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "listdevs - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "listdevs - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "listdevs - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "../Win32/Release/examples"
+# PROP Intermediate_Dir "../Win32/Release/examples/listdevs"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../libusb" /I "." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /U "_MBCS" /FR /FD /EHsc /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "listdevs - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "../Win32/Debug/examples"
+# PROP Intermediate_Dir "../Win32/Debug/examples/listdevs"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../libusb" /I "." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /U "_MBCS" /FR /FD /GZ /EHsc /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /n "../Win32/Debug/dll/core.sbr" "../Win32/Debug/dll/descriptor.sbr" "../Win32/Debug/dll/io.sbr" "../Win32/Debug/dll/sync.sbr" "../Win32/Debug/dll/poll_windows.sbr" "../Win32/Debug/dll/threads_windows.sbr" "../Win32/Debug/dll/windows_usb.sbr"
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF 
+
+# Begin Target
+
+# Name "listdevs - Win32 Release"
+# Name "listdevs - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\examples\listdevs.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project

+ 360 - 0
compat/libusb-1.0/msvc/listdevs.vcproj

@@ -0,0 +1,360 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="listdevs"
+	ProjectGUID="{98CFD8FA-EE20-40D5-AF13-F8C4856D6CA5}"
+	RootNamespace="examples"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="..\$(PlatformName)\$(ConfigurationName)\examples"
+			IntermediateDirectory="..\$(PlatformName)\$(ConfigurationName)\examples\$(ProjectName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\libusb"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="..\$(PlatformName)\$(ConfigurationName)\examples"
+			IntermediateDirectory="..\$(PlatformName)\$(ConfigurationName)\examples\$(ProjectName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="..\libusb"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="..\$(PlatformName)\$(ConfigurationName)\examples"
+			IntermediateDirectory="..\$(PlatformName)\$(ConfigurationName)\examples\$(ProjectName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\libusb"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="..\$(PlatformName)\$(ConfigurationName)\examples"
+			IntermediateDirectory="..\$(PlatformName)\$(ConfigurationName)\examples\$(ProjectName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="..\libusb"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\examples\listdevs.c"
+				>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Detect64BitPortabilityProblems="false"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						Detect64BitPortabilityProblems="false"
+					/>
+				</FileConfiguration>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

+ 165 - 0
compat/libusb-1.0/msvc/listdevs.vcxproj

@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectName>listdevs</ProjectName>
+    <ProjectGuid>{F4938DB0-3DE7-4737-9C5A-EAD1BE819F87}</ProjectGuid>
+    <RootNamespace>examples</RootNamespace>
+    <Keyword>Win32Proj</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)..\$(Platform)\$(Configuration)\examples\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\$(Platform)\$(Configuration)\examples\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)..\$(Platform)\$(Configuration)\examples\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)..\$(Platform)\$(Configuration)\examples\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)..\$(Platform)\$(Configuration)\examples\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <BuildLog>
+      <Path>$(IntDir)$(ProjectName).htm</Path>
+    </BuildLog>
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile>
+      <SubSystem>Console</SubSystem>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <BuildLog>
+      <Path>$(IntDir)$(ProjectName).htm</Path>
+    </BuildLog>
+    <Midl>
+      <TargetEnvironment>X64</TargetEnvironment>
+    </Midl>
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile>
+      <SubSystem>Console</SubSystem>
+      <TargetMachine>MachineX64</TargetMachine>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <BuildLog>
+      <Path>$(IntDir)$(ProjectName).htm</Path>
+    </BuildLog>
+    <ClCompile>
+      <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+    </ClCompile>
+    <Link>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile>
+      <SubSystem>Console</SubSystem>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <BuildLog>
+      <Path>$(IntDir)$(ProjectName).htm</Path>
+    </BuildLog>
+    <Midl>
+      <TargetEnvironment>X64</TargetEnvironment>
+    </Midl>
+    <ClCompile>
+      <AdditionalIncludeDirectories>..\libusb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+    </ClCompile>
+    <Link>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <ProgramDatabaseFile>$(TargetDir)$(ProjectName).pdb</ProgramDatabaseFile>
+      <SubSystem>Console</SubSystem>
+      <TargetMachine>MachineX64</TargetMachine>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\examples\listdevs.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include=".\libusb_static.vcxproj">
+      <Project>{349ee8f9-7d25-4909-aaf5-ff3fade72187}</Project>
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 14 - 0
compat/libusb-1.0/msvc/listdevs.vcxproj.filters

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\examples\listdevs.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>

+ 19 - 0
compat/libusb-1.0/msvc/listdevs_sources

@@ -0,0 +1,19 @@
+TARGETNAME=listdevs
+TARGETTYPE=PROGRAM
+386_STDCALL=0
+
+_NT_TARGET_VERSION= $(_NT_TARGET_VERSION_WINXP)
+!IFNDEF MSC_WARNING_LEVEL
+MSC_WARNING_LEVEL=/W3
+!ENDIF
+
+!IFDEF STATIC_LIBC
+USE_LIBCMT=1
+!ELSE
+USE_MSVCRT=1
+!ENDIF
+
+UMTYPE=console
+INCLUDES=..\..\libusb;$(DDK_INC_PATH)
+UMLIBS=..\..\libusb\os\obj$(BUILD_ALT_DIR)\*\libusb-1.0.lib
+SOURCES=..\listdevs.c

+ 256 - 0
compat/libusb-1.0/msvc/stdint.h

@@ -0,0 +1,256 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file was originally part of the w64 mingw-runtime package.
+ */
+
+/* ISO C9x  7.18  Integer types <stdint.h>
+ * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794)
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  Contributor: Danny Smith <danny_r_smith_2001@yahoo.co.nz>
+ *  Modified for libusb/MSVC: Pete Batard <pbatard@gmail.com>
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *  Date: 2010-04-02
+ */
+
+#ifndef _MSC_VER
+#error This header should only be used with Microsoft compilers
+#endif
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+#ifndef _INTPTR_T_DEFINED
+#define _INTPTR_T_DEFINED
+#ifndef __intptr_t_defined
+#define __intptr_t_defined
+#undef intptr_t
+#ifdef _WIN64
+  typedef __int64 intptr_t;
+#else
+  typedef int intptr_t;
+#endif /* _WIN64 */
+#endif /* __intptr_t_defined */
+#endif /* _INTPTR_T_DEFINED */
+
+#ifndef _UINTPTR_T_DEFINED
+#define _UINTPTR_T_DEFINED
+#ifndef __uintptr_t_defined
+#define __uintptr_t_defined
+#undef uintptr_t
+#ifdef _WIN64
+  typedef unsigned __int64 uintptr_t;
+#else
+  typedef unsigned int uintptr_t;
+#endif /* _WIN64 */
+#endif /* __uintptr_t_defined */
+#endif /* _UINTPTR_T_DEFINED */
+
+#ifndef _PTRDIFF_T_DEFINED
+#define _PTRDIFF_T_DEFINED
+#ifndef _PTRDIFF_T_
+#define _PTRDIFF_T_
+#undef ptrdiff_t
+#ifdef _WIN64
+  typedef __int64 ptrdiff_t;
+#else
+  typedef int ptrdiff_t;
+#endif /* _WIN64 */
+#endif /* _PTRDIFF_T_ */
+#endif /* _PTRDIFF_T_DEFINED */
+
+#ifndef _WCHAR_T_DEFINED
+#define _WCHAR_T_DEFINED
+#ifndef __cplusplus
+  typedef unsigned short wchar_t;
+#endif /* C++ */
+#endif /* _WCHAR_T_DEFINED */
+
+#ifndef _WCTYPE_T_DEFINED
+#define _WCTYPE_T_DEFINED
+#ifndef _WINT_T
+#define _WINT_T
+  typedef unsigned short wint_t;
+  typedef unsigned short wctype_t;
+#endif /* _WINT_T */
+#endif /* _WCTYPE_T_DEFINED */
+
+/* 7.18.1.1  Exact-width integer types */
+typedef __int8 int8_t;
+typedef unsigned __int8   uint8_t;
+typedef __int16  int16_t;
+typedef unsigned __int16  uint16_t;
+typedef __int32  int32_t;
+typedef unsigned __int32  uint32_t;
+typedef __int64  int64_t;
+typedef unsigned __int64   uint64_t;
+
+/* 7.18.1.2  Minimum-width integer types */
+typedef signed char int_least8_t;
+typedef unsigned char   uint_least8_t;
+typedef short  int_least16_t;
+typedef unsigned short  uint_least16_t;
+typedef int  int_least32_t;
+typedef unsigned   uint_least32_t;
+typedef __int64  int_least64_t;
+typedef unsigned __int64   uint_least64_t;
+
+/*  7.18.1.3  Fastest minimum-width integer types
+ *  Not actually guaranteed to be fastest for all purposes
+ *  Here we use the exact-width types for 8 and 16-bit ints.
+ */
+typedef __int8 int_fast8_t;
+typedef unsigned __int8 uint_fast8_t;
+typedef __int16  int_fast16_t;
+typedef unsigned __int16  uint_fast16_t;
+typedef __int32  int_fast32_t;
+typedef unsigned  __int32  uint_fast32_t;
+typedef __int64  int_fast64_t;
+typedef unsigned __int64   uint_fast64_t;
+
+/* 7.18.1.5  Greatest-width integer types */
+typedef __int64  intmax_t;
+typedef unsigned __int64   uintmax_t;
+
+/* 7.18.2  Limits of specified-width integer types */
+
+/* 7.18.2.1  Limits of exact-width integer types */
+#define INT8_MIN (-128)
+#define INT16_MIN (-32768)
+#define INT32_MIN (-2147483647 - 1)
+#define INT64_MIN  (-9223372036854775807LL - 1)
+
+#define INT8_MAX 127
+#define INT16_MAX 32767
+#define INT32_MAX 2147483647
+#define INT64_MAX 9223372036854775807LL
+
+#define UINT8_MAX 255
+#define UINT16_MAX 65535
+#define UINT32_MAX 0xffffffffU  /* 4294967295U */
+#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
+
+/* 7.18.2.2  Limits of minimum-width integer types */
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST64_MIN INT64_MIN
+
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MAX INT64_MAX
+
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+/* 7.18.2.3  Limits of fastest minimum-width integer types */
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST64_MIN INT64_MIN
+
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MAX INT64_MAX
+
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+/* 7.18.2.4  Limits of integer types capable of holding
+    object pointers */
+#ifdef _WIN64
+#define INTPTR_MIN INT64_MIN
+#define INTPTR_MAX INT64_MAX
+#define UINTPTR_MAX UINT64_MAX
+#else
+#define INTPTR_MIN INT32_MIN
+#define INTPTR_MAX INT32_MAX
+#define UINTPTR_MAX UINT32_MAX
+#endif
+
+/* 7.18.2.5  Limits of greatest-width integer types */
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+/* 7.18.3  Limits of other integer types */
+#ifdef _WIN64
+#define PTRDIFF_MIN INT64_MIN
+#define PTRDIFF_MAX INT64_MAX
+#else
+#define PTRDIFF_MIN INT32_MIN
+#define PTRDIFF_MAX INT32_MAX
+#endif
+
+#define SIG_ATOMIC_MIN INT32_MIN
+#define SIG_ATOMIC_MAX INT32_MAX
+
+#ifndef SIZE_MAX
+#ifdef _WIN64
+#define SIZE_MAX UINT64_MAX
+#else
+#define SIZE_MAX UINT32_MAX
+#endif
+#endif
+
+#ifndef WCHAR_MIN  /* also in wchar.h */
+#define WCHAR_MIN 0U
+#define WCHAR_MAX 0xffffU
+#endif
+
+/*
+ * wint_t is unsigned short for compatibility with MS runtime
+ */
+#define WINT_MIN 0U
+#define WINT_MAX 0xffffU
+
+
+/* 7.18.4  Macros for integer constants */
+
+/* 7.18.4.1  Macros for minimum-width integer constants
+
+    Accoding to Douglas Gwyn <gwyn@arl.mil>:
+	"This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
+	9899:1999 as initially published, the expansion was required
+	to be an integer constant of precisely matching type, which
+	is impossible to accomplish for the shorter types on most
+	platforms, because C99 provides no standard way to designate
+	an integer constant with width less than that of type int.
+	TC1 changed this to require just an integer constant
+	*expression* with *promoted* type."
+
+	The trick used here is from Clive D W Feather.
+*/
+
+#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val))
+#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val))
+#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val))
+/*  The 'trick' doesn't work in C89 for long long because, without
+    suffix, (val) will be evaluated as int, not intmax_t */
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) (val)
+#define UINT16_C(val) (val)
+#define UINT32_C(val) (val##i32)
+#define UINT64_C(val) val##ui64
+
+/* 7.18.4.2  Macros for greatest-width integer constants */
+#define INTMAX_C(val) val##i64
+#define UINTMAX_C(val) val##ui64
+
+#endif

+ 12 - 14
configure.ac

@@ -82,6 +82,9 @@ case $target in
 esac
 
 case $target in
+  *-*-linux-gnu*)
+    have_linux=true
+    ;;
   *-*-mingw*)
     have_win32=true
     PTHREAD_FLAGS=""
@@ -308,7 +311,7 @@ else
 fi
 
 AM_CONDITIONAL([NEED_FPGAUTILS], [test x$modminer$ztex != xnono])
-AM_CONDITIONAL([NEED_USBUTILS_C], [test x$avalon$bitforce$modminer$bflsc$icarus != xnonononono])
+AM_CONDITIONAL([WANT_USBUTILS], [test x$avalon$bitforce$modminer$bflsc$icarus != xnonononono])
 AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes])
 AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue])
 AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue])
@@ -316,6 +319,13 @@ AM_CONDITIONAL([HAVE_x86_64], [test x$have_x86_64 = xtrue])
 
 if test "x$avalon$bitforce$modminer$bflsc$icarus" != xnonononono; then
 	AC_DEFINE([USE_USBUTILS], [1], [Defined to 1 if usbutils support required])
+	LIBUSB_LIBS="compat/libusb-1.0/libusb/.libs/libusb-1.0.a"
+	AC_CONFIG_SUBDIRS([compat/libusb-1.0])
+	if test "x$have_linux" = "xtrue"; then
+		PKG_CHECK_MODULES([UDEV], [libudev], LIBUSB_LIBS+=" -ludev", [AC_MSG_ERROR([Missing required libudev dev])])
+	fi
+else
+	LIBUSB_LIBS=""
 fi
 
 if test x$request_jansson = xtrue
@@ -337,18 +347,6 @@ if test "x$have_cgminer_sdk" = "xtrue"; then
 	PKG_CONFIG_PATH="$CGMINER_SDK/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
 fi
 
-if test "x$avalon$ztex$modminer$bitforce$bflsc$icarus" != xnononononono; then
-  case $target in
-    *-*-freebsd*)
-      LIBUSB_LIBS="-lusb"
-      LIBUSB_CFLAGS=""
-      AC_DEFINE(HAVE_LIBUSB, 1, [Define if you have libusb-1.0])
-      ;;
-    *)
-      PKG_CHECK_MODULES(LIBUSB, libusb-1.0, [AC_DEFINE(HAVE_LIBUSB, 1, [Define if you have libusb-1.0])], [AC_MSG_ERROR([Could not find usb library - please install libusb-1.0])])
-      ;;
-  esac
-fi
 AC_SUBST(LIBUSB_LIBS)
 AC_SUBST(LIBUSB_CFLAGS)
 
@@ -525,7 +523,7 @@ fi
 echo
 echo "Compilation............: make (or gmake)"
 echo "  CPPFLAGS.............: $CPPFLAGS"
-echo "  CFLAGS...............: $CFLAGS $LIBUSB_CFLAGS"
+echo "  CFLAGS...............: $CFLAGS"
 echo "  LDFLAGS..............: $LDFLAGS $PTHREAD_FLAGS"
 echo "  LDADD................: $DLOPEN_FLAGS $LIBCURL_LIBS $JANSSON_LIBS $PTHREAD_LIBS $OPENCL_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $MATH_LIBS $LIBUSB_LIBS"
 echo