Add libusb v1.0.9

Change-Id: Ib2d76c36a6caffcf69d03a8798ca2c2222c85ae7
Signed-off-by: Adam Hampson <ahampson@google.com>
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..b43d995
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,45 @@
+Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
+Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+Copyright (C) 2008-2012 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
+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
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..ad12fcd
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,40 @@
+# Copyright 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This makefile builds both for host and target, and so all the
+# common definitions are factored out into a separate file to
+# minimize duplication between the build rules.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    libusb/core.c \
+    libusb/descriptor.c \
+    libusb/io.c \
+    libusb/sync.c \
+    libusb/os/linux_usbfs.c \
+    libusb/os/threads_posix.c
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/libusb \
+    $(LOCAL_PATH)/..
+
+LOCAL_SHARED_LIBRARIES := \
+    libc
+
+LOCAL_MODULE:= libusb
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5ab7695
--- /dev/null
+++ b/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!
+
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..5458714
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,234 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006 Free Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about.  Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/MODULE_LICENSE_LGPL b/MODULE_LICENSE_LGPL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_LGPL
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..ce7b7e2
--- /dev/null
+++ b/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)
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..f948700
--- /dev/null
+++ b/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
+
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..5ab7695
--- /dev/null
+++ b/NOTICE
@@ -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!
+
+
diff --git a/PORTING b/PORTING
new file mode 100644
index 0000000..7070784
--- /dev/null
+++ b/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.
+
diff --git a/README b/README
new file mode 100644
index 0000000..08ae169
--- /dev/null
+++ b/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)
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
new file mode 100644
index 0000000..b8fe795
--- /dev/null
+++ b/RELEASE-NOTES
@@ -0,0 +1,35 @@
+libusb 1.0.9
+
+This release has taken much too long to finish, but this also means that it
+has a long list of bugs fixes and many other improvements.
+
+Perhaps the most exciting improvement is the addition of the backend for
+Microsoft Windows, which closes ticket #1.
+
+A very special thanks goes to Pete Batard, Michael Plante, Tim Roberts,
+Orin Eman, Graeme Gill, and everyone else in the community who help work
+on the Windows support!
+
+Because Windows is a peculiar beast you may encounter some bugs when using
+this first release with the Windows backend. In that case, please get in
+touch with the libusb community so that we can help resolve them. File a
+ticket at http://libusb.org/newticket or let us know via email or on IRC.
+Visit http://libusb.org/ for all contact details.
+
+Another exciting improvement is the new OpenBSD backend, which also works
+on NetBSD systems.
+
+All known downstream bugs and all known severe bugs reported directly to
+libusb.org have been fixed in this release, so please report new ones!
+
+
+This release would not have been what it is without help, code, reports,
+and advice from friends like these:
+
+ Alan Ott, Alan Stern, Brian Shirley, Dave Camarillo, Graeme Gill,
+ Hans de Goede, Hector Martin, James Hanko, Konrad Rzepecki,
+ Ludovic Rousseau, Martin Pieuchot, Mike Frysinger, Orin Eman,
+ Pekka Nikander, Pete Batard, Sean McBride, Sebastian Pipping,
+ Stephan Meyer, Thomas Röfer, Trygve Laugstøl, Vitali Lovich, Xiaofan Chen
+
+	Thanks!
diff --git a/THANKS b/THANKS
new file mode 100644
index 0000000..d926126
--- /dev/null
+++ b/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
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..6c162a3
--- /dev/null
+++ b/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
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..c7bb679
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# use libtoolize if available, otherwise look for glibtoolize (darwin)
+if (libtoolize --version) < /dev/null > /dev/null 2>&1; then
+  LIBTOOLIZE=libtoolize
+elif (glibtoolize --version) < /dev/null > /dev/null 2>&1; then
+  LIBTOOLIZE=glibtoolize
+else
+  echo "libtoolize or glibtoolize was not found! Please install libtool."
+  exit
+fi
+
+$LIBTOOLIZE --copy --force || exit 1
+aclocal || exit 1
+autoheader || exit 1
+autoconf || exit 1
+automake -a -c || exit 1
+./configure --enable-maintainer-mode --enable-debug-log \
+	--enable-examples-build $*
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..52d50ee
--- /dev/null
+++ b/config.h
@@ -0,0 +1,117 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+#define LIBUSB_DESCRIBE ""
+#undef USBI_TIMERFD_AVAILABLE
+
+/* Default visibility */
+#define DEFAULT_VISIBILITY __attribute__((visibility("default")))
+
+/* Debug message logging */
+/* #undef ENABLE_DEBUG_LOGGING */
+
+/* Message logging */
+#define ENABLE_LOGGING 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if the system has the type `struct timespec'. */
+#define HAVE_STRUCT_TIMESPEC 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Darwin backend */
+/* #undef OS_DARWIN */
+
+/* Linux backend */
+#define OS_LINUX 1
+
+/* OpenBSD backend */
+/* #undef OS_OPENBSD */
+
+/* Windows backend */
+/* #undef OS_WINDOWS */
+
+/* Name of package */
+#define PACKAGE "libusb"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "libusb-devel@lists.sourceforge.net"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libusb"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libusb 1.0.9"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libusb"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL "http://www.libusb.org/"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.0.9"
+
+/* type of second poll() argument */
+#define POLL_NFDS_TYPE nfds_t
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Use POSIX Threads */
+#define THREADS_POSIX 1
+
+/* Version number of package */
+#define VERSION "1.0.9"
+
+/* Use GNU extensions */
+#define _GNU_SOURCE 1
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..f9e648e
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,222 @@
+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="1"
+lt_revision="0"
+lt_age="1"
+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])
+AM_CONFIG_HEADER([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, PC_LIBS_PRIVATE="-lrt")
+	threads="posix"
+	THREAD_CFLAGS="-pthread"
+	PC_LIBS_PRIVATE="${PC_LIBS_PRIVATE} -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"
+	PC_LIBS_PRIVATE="-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"
+	PC_LIBS_PRIVATE="-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)
+	PC_LIBS_PRIVATE=""
+	LTLDFLAGS="${LTLDFLAGS} -avoid-version -Wl,--add-stdcall-alias"
+	AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])
+	;;
+esac
+AC_SUBST(THREAD_CFLAGS)
+AC_SUBST(PC_LIBS_PRIVATE)
+LIBS="${LIBS} ${PC_LIBS_PRIVATE}"
+
+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)
+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"
+
+AC_SUBST(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
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..931a7c0
--- /dev/null
+++ b/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
+
diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in
new file mode 100644
index 0000000..128e1de
--- /dev/null
+++ b/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
+
+# 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
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..c7630d2
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,21 @@
+INCLUDES = -I$(top_srcdir)/libusb
+noinst_PROGRAMS = listdevs
+
+listdevs_SOURCES = listdevs.c
+listdevs_LDADD = ../libusb/libusb-1.0.la
+
+if HAVE_SIGACTION
+dpfp_SOURCES = dpfp.c
+dpfp_LDADD = ../libusb/libusb-1.0.la
+noinst_PROGRAMS += dpfp
+endif
+
+if THREADS_POSIX
+if HAVE_SIGACTION
+dpfp_threaded_SOURCES = dpfp_threaded.c
+dpfp_threaded_CFLAGS = $(THREAD_CFLAGS) $(AM_CFLAGS)
+dpfp_threaded_LDADD = ../libusb/libusb-1.0.la
+noinst_PROGRAMS += dpfp_threaded
+endif
+endif
+
diff --git a/examples/dpfp.c b/examples/dpfp.c
new file mode 100644
index 0000000..ecd5a92
--- /dev/null
+++ b/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;
+}
+
diff --git a/examples/dpfp_threaded.c b/examples/dpfp_threaded.c
new file mode 100644
index 0000000..93de9d7
--- /dev/null
+++ b/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;
+}
+
diff --git a/examples/listdevs.c b/examples/listdevs.c
new file mode 100644
index 0000000..6ab8917
--- /dev/null
+++ b/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;
+}
+
diff --git a/libusb-1.0.pc.in b/libusb-1.0.pc.in
new file mode 100644
index 0000000..f26babc
--- /dev/null
+++ b/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: @PC_LIBS_PRIVATE@
+Cflags: -I${includedir}/libusb-1.0
+
diff --git a/libusb/Makefile.am b/libusb/Makefile.am
new file mode 100644
index 0000000..3316ebc
--- /dev/null
+++ b/libusb/Makefile.am
@@ -0,0 +1,49 @@
+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
+
+if OS_LINUX
+OS_SRC = $(LINUX_USBFS_SRC)
+endif
+
+if OS_DARWIN
+OS_SRC = $(DARWIN_USB_SRC)
+AM_CFLAGS_EXT = -no-cpp-precomp
+endif
+
+if OS_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 = $(VISIBILITY_CFLAGS) $(AM_CFLAGS) $(THREAD_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) \
+	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
diff --git a/libusb/core.c b/libusb/core.c
new file mode 100644
index 0000000..767dcbf
--- /dev/null
+++ b/libusb/core.c
@@ -0,0 +1,1875 @@
+/*
+ * Core functions for libusb
+ * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include "libusbi.h"
+
+#if defined(OS_LINUX)
+const struct usbi_os_backend * const usbi_backend = &linux_usbfs_backend;
+#elif defined(OS_DARWIN)
+const struct usbi_os_backend * const usbi_backend = &darwin_backend;
+#elif defined(OS_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;
+
+/**
+ * \mainpage libusb-1.0 API Reference
+ *
+ * \section intro Introduction
+ *
+ * libusb is an open source library that allows you to communicate with USB
+ * devices from userspace. For more info, see the
+ * <a href="http://libusb.sourceforge.net">libusb homepage</a>.
+ *
+ * This documentation is aimed at application developers wishing to
+ * communicate with USB peripherals from their own software. After reviewing
+ * this documentation, feedback and questions can be sent to the
+ * <a href="http://sourceforge.net/mail/?group_id=1674">libusb-devel mailing
+ * list</a>.
+ *
+ * This documentation assumes knowledge of how to operate USB devices from
+ * a software standpoint (descriptors, configurations, interfaces, endpoints,
+ * control/bulk/interrupt/isochronous transfers, etc). Full information
+ * can be found in the <a href="http://www.usb.org/developers/docs/">USB 2.0
+ * Specification</a> which is available for free download. You can probably
+ * find less verbose introductions by searching the web.
+ *
+ * \section features Library features
+ *
+ * - All transfer types supported (control/bulk/interrupt/isochronous)
+ * - 2 transfer interfaces:
+ *    -# Synchronous (simple)
+ *    -# Asynchronous (more complicated, but more powerful)
+ * - Thread safe (although the asynchronous interface means that you
+ *   usually won't need to thread)
+ * - Lightweight with lean API
+ * - Compatible with libusb-0.1 through the libusb-compat-0.1 translation layer
+ *
+ * \section gettingstarted Getting Started
+ *
+ * To begin reading the API documentation, start with the Modules page which
+ * links to the different categories of libusb's functionality.
+ *
+ * One decision you will have to make is whether to use the synchronous
+ * or the asynchronous data transfer interface. The \ref io documentation
+ * provides some insight into this topic.
+ *
+ * Some example programs can be found in the libusb source distribution under
+ * the "examples" subdirectory. The libusb homepage includes a list of
+ * real-life project examples which use libusb.
+ *
+ * \section errorhandling Error handling
+ *
+ * libusb functions typically return 0 on success or a negative error code
+ * on failure. These negative error codes relate to LIBUSB_ERROR constants
+ * which are listed on the \ref misc "miscellaneous" documentation page.
+ *
+ * \section msglog Debug message logging
+ *
+ * libusb does not log any messages by default. Your application is therefore
+ * free to close stdout/stderr and those descriptors may be reused without
+ * worry.
+ *
+ * The libusb_set_debug() function can be used to enable stdout/stderr logging
+ * of certain messages. Under standard configuration, libusb doesn't really
+ * log much at all, so you are advised to use this function to enable all
+ * error/warning/informational messages. It will help you debug problems with
+ * your software.
+ *
+ * The logged messages are unstructured. There is no one-to-one correspondence
+ * between messages being logged and success or failure return codes from
+ * libusb functions. There is no format to the messages, so you should not
+ * try to capture or parse them. They are not and will not be localized.
+ * These messages are not suitable for being passed to your application user;
+ * instead, you should interpret the error codes returned from libusb functions
+ * and provide appropriate notification to the user. The messages are simply
+ * there to aid you as a programmer, and if you're confused because you're
+ * getting a strange error code from a libusb function, enabling message
+ * logging may give you a suitable explanation.
+ *
+ * The LIBUSB_DEBUG environment variable can be used to enable message logging
+ * at run-time. This environment variable should be set to a number, which is
+ * interpreted the same as the libusb_set_debug() parameter. When this
+ * environment variable is set, the message logging verbosity level is fixed
+ * and libusb_set_debug() effectively does nothing.
+ *
+ * libusb can be compiled without any logging functions, useful for embedded
+ * systems. In this case, libusb_set_debug() and the LIBUSB_DEBUG environment
+ * variable have no effects.
+ *
+ * libusb can also be compiled with verbose debugging messages. When the
+ * library is compiled in this way, all messages of all verbosities are always
+ * logged.  libusb_set_debug() and the LIBUSB_DEBUG environment variable have
+ * no effects.
+ *
+ * \section remarks Other remarks
+ *
+ * libusb does have imperfections. The \ref caveats "caveats" page attempts
+ * to document these.
+ */
+
+/**
+ * \page caveats Caveats
+ *
+ * \section devresets Device resets
+ *
+ * The libusb_reset_device() function allows you to reset a device. If your
+ * program has to call such a function, it should obviously be aware that
+ * the reset will cause device state to change (e.g. register values may be
+ * reset).
+ *
+ * The problem is that any other program could reset the device your program
+ * is working with, at any time. libusb does not offer a mechanism to inform
+ * you when this has happened, so if someone else resets your device it will
+ * not be clear to your own program why the device state has changed.
+ *
+ * Ultimately, this is a limitation of writing drivers in userspace.
+ * Separation from the USB stack in the underlying kernel makes it difficult
+ * for the operating system to deliver such notifications to your program.
+ * The Linux kernel USB stack allows such reset notifications to be delivered
+ * to in-kernel USB drivers, but it is not clear how such notifications could
+ * be delivered to second-class drivers that live in userspace.
+ *
+ * \section blockonly Blocking-only functionality
+ *
+ * The functionality listed below is only available through synchronous,
+ * blocking functions. There are no asynchronous/non-blocking alternatives,
+ * and no clear ways of implementing these.
+ *
+ * - Configuration activation (libusb_set_configuration())
+ * - Interface/alternate setting activation (libusb_set_interface_alt_setting())
+ * - Releasing of interfaces (libusb_release_interface())
+ * - Clearing of halt/stall condition (libusb_clear_halt())
+ * - Device resets (libusb_reset_device())
+ *
+ * \section nohotplug No hotplugging
+ *
+ * libusb-1.0 lacks functionality for providing notifications of when devices
+ * are added or removed. This functionality is planned to be implemented
+ * for libusb-1.1.
+ *
+ * That said, there is basic disconnection handling for open device handles:
+ *  - If there are ongoing transfers, libusb's handle_events loop will detect
+ *    disconnections and complete ongoing transfers with the
+ *    LIBUSB_TRANSFER_NO_DEVICE status code.
+ *  - Many functions such as libusb_set_configuration() return the special
+ *    LIBUSB_ERROR_NO_DEVICE error code when the device has been disconnected.
+ *
+ * \section configsel Configuration selection and handling
+ *
+ * When libusb presents a device handle to an application, there is a chance
+ * that the corresponding device may be in unconfigured state. For devices
+ * with multiple configurations, there is also a chance that the configuration
+ * currently selected is not the one that the application wants to use.
+ *
+ * The obvious solution is to add a call to libusb_set_configuration() early
+ * on during your device initialization routines, but there are caveats to
+ * be aware of:
+ * -# If the device is already in the desired configuration, calling
+ *    libusb_set_configuration() using the same configuration value will cause
+ *    a lightweight device reset. This may not be desirable behaviour.
+ * -# libusb will be unable to change configuration if the device is in
+ *    another configuration and other programs or drivers have claimed
+ *    interfaces under that configuration.
+ * -# In the case where the desired configuration is already active, libusb
+ *    may not even be able to perform a lightweight device reset. For example,
+ *    take my USB keyboard with fingerprint reader: I'm interested in driving
+ *    the fingerprint reader interface through libusb, but the kernel's
+ *    USB-HID driver will almost always have claimed the keyboard interface.
+ *    Because the kernel has claimed an interface, it is not even possible to
+ *    perform the lightweight device reset, so libusb_set_configuration() will
+ *    fail. (Luckily the device in question only has a single configuration.)
+ *
+ * One solution to some of the above problems is to consider the currently
+ * active configuration. If the configuration we want is already active, then
+ * we don't have to select any configuration:
+\code
+cfg = libusb_get_configuration(dev);
+if (cfg != desired)
+	libusb_set_configuration(dev, desired);
+\endcode
+ *
+ * This is probably suitable for most scenarios, but is inherently racy:
+ * another application or driver may change the selected configuration
+ * <em>after</em> the libusb_get_configuration() call.
+ *
+ * Even in cases where libusb_set_configuration() succeeds, consider that other
+ * applications or drivers may change configuration after your application
+ * calls libusb_set_configuration().
+ *
+ * One possible way to lock your device into a specific configuration is as
+ * follows:
+ * -# Set the desired configuration (or use the logic above to realise that
+ *    it is already in the desired configuration)
+ * -# Claim the interface that you wish to use
+ * -# Check that the currently active configuration is the one that you want
+ *    to use.
+ *
+ * The above method works because once an interface is claimed, no application
+ * or driver is able to select another configuration.
+ *
+ * \section earlycomp Early transfer completion
+ *
+ * NOTE: This section is currently Linux-centric. I am not sure if any of these
+ * considerations apply to Darwin or other platforms.
+ *
+ * When a transfer completes early (i.e. when less data is received/sent in
+ * any one packet than the transfer buffer allows for) then libusb is designed
+ * to terminate the transfer immediately, not transferring or receiving any
+ * more data unless other transfers have been queued by the user.
+ *
+ * On legacy platforms, libusb is unable to do this in all situations. After
+ * the incomplete packet occurs, "surplus" data may be transferred. Prior to
+ * libusb v1.0.2, this information was lost (and for device-to-host transfers,
+ * the corresponding data was discarded). As of libusb v1.0.3, this information
+ * is kept (the data length of the transfer is updated) and, for device-to-host
+ * transfers, any surplus data was added to the buffer. Still, this is not
+ * a nice solution because it loses the information about the end of the short
+ * packet, and the user probably wanted that surplus data to arrive in the next
+ * logical transfer.
+ *
+ * A previous workaround was to only ever submit transfers of size 16kb or
+ * less.
+ *
+ * As of libusb v1.0.4 and Linux v2.6.32, this is fixed. A technical
+ * explanation of this issue follows.
+ *
+ * When you ask libusb to submit a bulk transfer larger than 16kb in size,
+ * libusb breaks it up into a number of smaller subtransfers. This is because
+ * the usbfs kernel interface only accepts transfers of up to 16kb in size.
+ * The subtransfers are submitted all at once so that the kernel can queue
+ * them at the hardware level, therefore maximizing bus throughput.
+ *
+ * On legacy platforms, this caused problems when transfers completed early.
+ * Upon this event, the kernel would terminate all further packets in that
+ * subtransfer (but not any following ones). libusb would note this event and
+ * immediately cancel any following subtransfers that had been queued,
+ * but often libusb was not fast enough, and the following subtransfers had
+ * started before libusb got around to cancelling them.
+ *
+ * Thanks to an API extension to usbfs, this is fixed with recent kernel and
+ * libusb releases. The solution was to allow libusb to communicate to the
+ * kernel where boundaries occur between logical libusb-level transfers. When
+ * a short transfer (or other error) occurs, the kernel will cancel all the
+ * subtransfers until the boundary without allowing those transfers to start.
+ *
+ * \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);
+
+	usbi_mutex_lock(&ctx->usb_devs_lock);
+	list_add(&dev->list, &ctx->usb_devs);
+	usbi_mutex_unlock(&ctx->usb_devs_lock);
+	return dev;
+}
+
+/* Perform some final sanity checks on a newly discovered device. If this
+ * function fails (negative return code), the device should not be added
+ * to the discovered device list. */
+int usbi_sanitize_device(struct libusb_device *dev)
+{
+	int r;
+	unsigned char raw_desc[DEVICE_DESC_LENGTH];
+	uint8_t num_configurations;
+	int host_endian;
+
+	r = usbi_backend->get_device_descriptor(dev, raw_desc, &host_endian);
+	if (r < 0)
+		return r;
+
+	num_configurations = raw_desc[DEVICE_DESC_LENGTH - 1];
+	if (num_configurations > USB_MAXCONFIG) {
+		usbi_err(DEVICE_CTX(dev), "too many configurations");
+		return LIBUSB_ERROR_IO;
+	} else if (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;
+
+	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);
+
+		usbi_mutex_lock(&dev->ctx->usb_devs_lock);
+		list_del(&dev->list);
+		usbi_mutex_unlock(&dev->ctx->usb_devs_lock);
+
+		usbi_mutex_destroy(&dev->lock);
+		free(dev);
+	}
+}
+
+/*
+ * Interrupt the iteration of the event handling thread, so that it picks
+ * up the new fd.
+ */
+void usbi_fd_notification(struct libusb_context *ctx)
+{
+	unsigned char dummy = 1;
+	ssize_t r;
+
+	if (ctx == NULL)
+		return;
+
+	/* record that we are messing with poll fds */
+	usbi_mutex_lock(&ctx->pollfd_modify_lock);
+	ctx->pollfd_modify++;
+	usbi_mutex_unlock(&ctx->pollfd_modify_lock);
+
+	/* write some data on control pipe to interrupt event handlers */
+	r = usbi_write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
+	if (r <= 0) {
+		usbi_warn(ctx, "internal signalling write failed");
+		usbi_mutex_lock(&ctx->pollfd_modify_lock);
+		ctx->pollfd_modify--;
+		usbi_mutex_unlock(&ctx->pollfd_modify_lock);
+		return;
+	}
+
+	/* take event handling lock */
+	libusb_lock_events(ctx);
+
+	/* read the dummy data */
+	r = usbi_read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy));
+	if (r <= 0)
+		usbi_warn(ctx, "internal signalling read failed");
+
+	/* we're done with modifying poll fds */
+	usbi_mutex_lock(&ctx->pollfd_modify_lock);
+	ctx->pollfd_modify--;
+	usbi_mutex_unlock(&ctx->pollfd_modify_lock);
+
+	/* Release event handling lock and wake up event waiters */
+	libusb_unlock_events(ctx);
+}
+
+/** \ingroup dev
+ * Open a device and obtain a device handle. A handle allows you to perform
+ * I/O on the device in question.
+ *
+ * Internally, this function adds a reference to the device and makes it
+ * available to you through libusb_get_device(). This reference is removed
+ * during libusb_close().
+ *
+ * This is a non-blocking function; no requests are sent over the bus.
+ *
+ * \param dev the device to open
+ * \param handle output location for the returned device handle pointer. Only
+ * populated when the return code is 0.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NO_MEM on memory allocation failure
+ * \returns LIBUSB_ERROR_ACCESS if the user has insufficient permissions
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_open(libusb_device *dev,
+	libusb_device_handle **handle)
+{
+	struct libusb_context *ctx = DEVICE_CTX(dev);
+	struct libusb_device_handle *_handle;
+	size_t priv_size = usbi_backend->device_handle_priv_size;
+	int r;
+	usbi_dbg("open %d.%d", dev->bus_number, dev->device_address);
+
+	_handle = malloc(sizeof(*_handle) + priv_size);
+	if (!_handle)
+		return LIBUSB_ERROR_NO_MEM;
+
+	r = usbi_mutex_init(&_handle->lock, NULL);
+	if (r) {
+		free(_handle);
+		return LIBUSB_ERROR_OTHER;
+	}
+
+	_handle->dev = libusb_ref_device(dev);
+	_handle->claimed_interfaces = 0;
+	memset(&_handle->os_priv, 0, priv_size);
+
+	r = usbi_backend->open(_handle);
+	if (r < 0) {
+		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;
+
+	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->claimed_interfaces & (1 << interface_number))) {
+		usbi_mutex_unlock(&dev->lock);
+		return LIBUSB_ERROR_NOT_FOUND;
+	}
+	usbi_mutex_unlock(&dev->lock);
+
+	return usbi_backend->set_interface_altsetting(dev, interface_number,
+		alternate_setting);
+}
+
+/** \ingroup dev
+ * Clear the halt/stall condition for an endpoint. Endpoints with halt status
+ * are unable to receive or transmit data until the halt condition is stalled.
+ *
+ * You should cancel all pending transfers before attempting to clear the halt
+ * condition.
+ *
+ * This is a blocking function.
+ *
+ * \param dev a device handle
+ * \param endpoint the endpoint to clear halt status
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_clear_halt(libusb_device_handle *dev,
+	unsigned char endpoint)
+{
+	usbi_dbg("endpoint %x", endpoint);
+	return usbi_backend->clear_halt(dev, endpoint);
+}
+
+/** \ingroup dev
+ * Perform a USB port reset to reinitialize a device. The system will attempt
+ * to restore the previous configuration and alternate settings after the
+ * reset has completed.
+ *
+ * If the reset fails, the descriptors change, or the previous state cannot be
+ * restored, the device will appear to be disconnected and reconnected. This
+ * means that the device handle is no longer valid (you should close it) and
+ * rediscover the device. A return code of LIBUSB_ERROR_NOT_FOUND indicates
+ * when this is the case.
+ *
+ * This is a blocking function which usually incurs a noticeable delay.
+ *
+ * \param dev a handle of the device to reset
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the
+ * device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_reset_device(libusb_device_handle *dev)
+{
+	usbi_dbg("");
+	return usbi_backend->reset_device(dev);
+}
+
+/** \ingroup dev
+ * Determine if a kernel driver is active on an interface. If a kernel driver
+ * is active, you cannot claim the interface, and libusb will be unable to
+ * perform I/O.
+ *
+ * This functionality is not available on Windows.
+ *
+ * \param dev a device handle
+ * \param interface_number the interface to check
+ * \returns 0 if no kernel driver is active
+ * \returns 1 if a kernel driver is active
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality
+ * is not available
+ * \returns another LIBUSB_ERROR code on other failure
+ * \see libusb_detach_kernel_driver()
+ */
+int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev,
+	int interface_number)
+{
+	usbi_dbg("interface %d", interface_number);
+	if (usbi_backend->kernel_driver_active)
+		return usbi_backend->kernel_driver_active(dev, interface_number);
+	else
+		return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+/** \ingroup dev
+ * Detach a kernel driver from an interface. If successful, you will then be
+ * able to claim the interface and perform I/O.
+ *
+ * This functionality is not available on Darwin or Windows.
+ *
+ * \param dev a device handle
+ * \param interface_number the interface to detach the driver from
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active
+ * \returns LIBUSB_ERROR_INVALID_PARAM if the interface does not exist
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality
+ * is not available
+ * \returns another LIBUSB_ERROR code on other failure
+ * \see libusb_kernel_driver_active()
+ */
+int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev,
+	int interface_number)
+{
+	usbi_dbg("interface %d", interface_number);
+	if (usbi_backend->detach_kernel_driver)
+		return usbi_backend->detach_kernel_driver(dev, interface_number);
+	else
+		return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+/** \ingroup dev
+ * Re-attach an interface's kernel driver, which was previously detached
+ * using libusb_detach_kernel_driver(). This call is only effective on
+ * Linux and returns LIBUSB_ERROR_NOT_SUPPORTED on all other platforms.
+ *
+ * This functionality is not available on Darwin or Windows.
+ *
+ * \param dev a device handle
+ * \param interface_number the interface to attach the driver from
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active
+ * \returns LIBUSB_ERROR_INVALID_PARAM if the interface does not exist
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality
+ * is not available
+ * \returns LIBUSB_ERROR_BUSY if the driver cannot be attached because the
+ * interface is claimed by a program or driver
+ * \returns another LIBUSB_ERROR code on other failure
+ * \see libusb_kernel_driver_active()
+ */
+int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev,
+	int interface_number)
+{
+	usbi_dbg("interface %d", interface_number);
+	if (usbi_backend->attach_kernel_driver)
+		return usbi_backend->attach_kernel_driver(dev, interface_number);
+	else
+		return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+/** \ingroup lib
+ * Set message verbosity.
+ *  - Level 0: no messages ever printed by the library (default)
+ *  - Level 1: error messages are printed to stderr
+ *  - Level 2: warning and error messages are printed to stderr
+ *  - Level 3: informational messages are printed to stdout, warning and error
+ *    messages are printed to stderr
+ *
+ * The default level is 0, which means no messages are ever printed. If you
+ * choose to increase the message verbosity level, ensure that your
+ * application does not close the stdout/stderr file descriptors.
+ *
+ * You are advised to set level 3. libusb is conservative with its message
+ * logging and most of the time, will only log messages that explain error
+ * conditions and other oddities. This will help you debug your software.
+ *
+ * If the LIBUSB_DEBUG environment variable was set when libusb was
+ * initialized, this function does nothing: the message verbosity is fixed
+ * to the value in the environment variable.
+ *
+ * If libusb was compiled without any message logging, this function does
+ * nothing: you'll never get any messages.
+ *
+ * If libusb was compiled with verbose debug message logging, this function
+ * does nothing: you'll always get messages from all levels.
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param level debug level to set
+ */
+void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level)
+{
+	USBI_GET_CONTEXT(ctx);
+	if (!ctx->debug_fixed)
+		ctx->debug = level;
+}
+
+/** \ingroup lib
+ * Initialize libusb. This function must be called before calling any other
+ * libusb function.
+ *
+ * If you do not provide an output location for a context pointer, a default
+ * context will be created. If there was already a default context, it will
+ * be reused (and nothing will be initialized/reinitialized).
+ *
+ * \param context Optional output location for context pointer.
+ * Only valid on return code 0.
+ * \returns 0 on success, or a LIBUSB_ERROR code on failure
+ * \see contexts
+ */
+int API_EXPORTED libusb_init(libusb_context **context)
+{
+	char *dbg = getenv("LIBUSB_DEBUG");
+	struct libusb_context *ctx;
+	int r = 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);
+
+	if (usbi_backend->init) {
+		r = usbi_backend->init(ctx);
+		if (r)
+			goto err_free_ctx;
+	}
+
+	usbi_mutex_init(&ctx->usb_devs_lock, NULL);
+	usbi_mutex_init(&ctx->open_devs_lock, NULL);
+	list_init(&ctx->usb_devs);
+	list_init(&ctx->open_devs);
+
+	r = usbi_io_init(ctx);
+	if (r < 0) {
+		if (usbi_backend->exit)
+			usbi_backend->exit();
+		goto err_destroy_mutex;
+	}
+
+	if (context) {
+		*context = ctx;
+	} else if (!usbi_default_context) {
+		usbi_dbg("created default context");
+		usbi_default_context = ctx;
+		default_context_refcnt++;
+	}
+	usbi_mutex_static_unlock(&default_context_lock);
+
+	return 0;
+
+err_destroy_mutex:
+	usbi_mutex_destroy(&ctx->open_devs_lock);
+	usbi_mutex_destroy(&ctx->usb_devs_lock);
+err_free_ctx:
+	free(ctx);
+err_unlock:
+	usbi_mutex_static_unlock(&default_context_lock);
+	return r;
+}
+
+/** \ingroup lib
+ * Deinitialize libusb. Should be called after closing all open devices and
+ * before your application terminates.
+ * \param ctx the context to deinitialize, or NULL for the default context
+ */
+void API_EXPORTED libusb_exit(struct libusb_context *ctx)
+{
+	usbi_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);
+	}
+
+	/* a little sanity check. doesn't bother with open_devs locking because
+	 * unless there is an application bug, nobody will be accessing this. */
+	if (!list_empty(&ctx->open_devs))
+		usbi_warn(ctx, "application left some devices open");
+
+	usbi_io_exit(ctx);
+	if (usbi_backend->exit)
+		usbi_backend->exit();
+
+	usbi_mutex_destroy(&ctx->open_devs_lock);
+	usbi_mutex_destroy(&ctx->usb_devs_lock);
+	free(ctx);
+}
+
+/** \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;
+	}
+	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->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 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;
+}
diff --git a/libusb/descriptor.c b/libusb/descriptor.c
new file mode 100644
index 0000000..e358e9e
--- /dev/null
+++ b/libusb/descriptor.c
@@ -0,0 +1,730 @@
+/*
+ * USB descriptor handling functions for libusb
+ * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libusbi.h"
+
+#define DESC_HEADER_LENGTH		2
+#define DEVICE_DESC_LENGTH		18
+#define CONFIG_DESC_LENGTH		9
+#define INTERFACE_DESC_LENGTH		9
+#define ENDPOINT_DESC_LENGTH		7
+#define ENDPOINT_AUDIO_DESC_LENGTH	9
+
+/** @defgroup desc USB descriptors
+ * This page details how to examine the various standard USB descriptors
+ * for detected devices
+ */
+
+/* set host_endian if the w values are already in host endian format,
+ * as opposed to bus endian. */
+int usbi_parse_descriptor(unsigned char *source, const char *descriptor,
+	void *dest, int host_endian)
+{
+	unsigned char *sp = source, *dp = dest;
+	uint16_t w;
+	const char *cp;
+
+	for (cp = descriptor; *cp; cp++) {
+		switch (*cp) {
+			case 'b':	/* 8-bit byte */
+				*dp++ = *sp++;
+				break;
+			case 'w':	/* 16-bit word, convert from little endian to CPU */
+				dp += ((uintptr_t)dp & 1);	/* Align to word boundary */
+
+				if (host_endian) {
+					memcpy(dp, sp, 2);
+				} else {
+					w = (sp[1] << 8) | sp[0];
+					*((uint16_t *)dp) = w;
+				}
+				sp += 2;
+				dp += 2;
+				break;
+		}
+	}
+
+	return (int) (sp - source);
+}
+
+static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint)
+{
+	if (endpoint->extra)
+		free((unsigned char *) endpoint->extra);
+}
+
+static int parse_endpoint(struct libusb_context *ctx,
+	struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer,
+	int size, int host_endian)
+{
+	struct usb_descriptor_header header;
+	unsigned char *extra;
+	unsigned char *begin;
+	int parsed = 0;
+	int len;
+
+	usbi_parse_descriptor(buffer, "bb", &header, 0);
+
+	/* Everything should be fine being passed into here, but we sanity */
+	/*  check JIC */
+	if (header.bLength > size) {
+		usbi_err(ctx, "ran out of descriptors parsing");
+		return -1;
+	}
+
+	if (header.bDescriptorType != LIBUSB_DT_ENDPOINT) {
+		usbi_err(ctx, "unexpected descriptor %x (expected %x)",
+			header.bDescriptorType, LIBUSB_DT_ENDPOINT);
+		return parsed;
+	}
+
+	if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH)
+		usbi_parse_descriptor(buffer, "bbbbwbbb", endpoint, host_endian);
+	else if (header.bLength >= ENDPOINT_DESC_LENGTH)
+		usbi_parse_descriptor(buffer, "bbbbwb", endpoint, host_endian);
+
+	buffer += header.bLength;
+	size -= header.bLength;
+	parsed += header.bLength;
+
+	/* Skip over the rest of the Class Specific or Vendor Specific */
+	/*  descriptors */
+	begin = buffer;
+	while (size >= DESC_HEADER_LENGTH) {
+		usbi_parse_descriptor(buffer, "bb", &header, 0);
+
+		if (header.bLength < 2) {
+			usbi_err(ctx, "invalid descriptor length %d", header.bLength);
+			return -1;
+		}
+
+		/* If we find another "proper" descriptor then we're done  */
+		if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
+				(header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
+				(header.bDescriptorType == LIBUSB_DT_CONFIG) ||
+				(header.bDescriptorType == LIBUSB_DT_DEVICE))
+			break;
+
+		usbi_dbg("skipping descriptor %x", header.bDescriptorType);
+		buffer += header.bLength;
+		size -= header.bLength;
+		parsed += header.bLength;
+	}
+
+	/* Copy any unknown descriptors into a storage area for drivers */
+	/*  to later parse */
+	len = (int)(buffer - begin);
+	if (!len) {
+		endpoint->extra = NULL;
+		endpoint->extra_length = 0;
+		return parsed;
+	}
+
+	extra = malloc(len);
+	endpoint->extra = extra;
+	if (!extra) {
+		endpoint->extra_length = 0;
+		return LIBUSB_ERROR_NO_MEM;
+	}
+
+	memcpy(extra, begin, len);
+	endpoint->extra_length = len;
+
+	return parsed;
+}
+
+static void clear_interface(struct libusb_interface *usb_interface)
+{
+	int i;
+	int j;
+
+	if (usb_interface->altsetting) {
+		for (i = 0; i < usb_interface->num_altsetting; i++) {
+			struct libusb_interface_descriptor *ifp =
+				(struct libusb_interface_descriptor *)
+				usb_interface->altsetting + i;
+			if (ifp->extra)
+				free((void *) ifp->extra);
+			if (ifp->endpoint) {
+				for (j = 0; j < ifp->bNumEndpoints; j++)
+					clear_endpoint((struct libusb_endpoint_descriptor *)
+						ifp->endpoint + j);
+				free((void *) ifp->endpoint);
+			}
+		}
+		free((void *) usb_interface->altsetting);
+		usb_interface->altsetting = NULL;
+	}
+
+}
+
+static int parse_interface(libusb_context *ctx,
+	struct libusb_interface *usb_interface, unsigned char *buffer, int size,
+	int host_endian)
+{
+	int i;
+	int len;
+	int r;
+	int parsed = 0;
+	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))
+				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))
+				break;
+
+			usbi_dbg("skipping descriptor 0x%x\n", header.bDescriptorType);
+			buffer += header.bLength;
+			size -= header.bLength;
+		}
+
+		/* Copy any unknown descriptors into a storage area for */
+		/*  drivers to later parse */
+		len = (int)(buffer - begin);
+		if (len) {
+			/* FIXME: We should realloc and append here */
+			if (!config->extra_length) {
+				config->extra = malloc(len);
+				if (!config->extra) {
+					r = LIBUSB_ERROR_NO_MEM;
+					goto err;
+				}
+
+				memcpy((unsigned char *) config->extra, begin, len);
+				config->extra_length = len;
+			}
+		}
+
+		r = parse_interface(ctx, usb_interface + i, buffer, size, host_endian);
+		if (r < 0)
+			goto err;
+
+		buffer += r;
+		size -= r;
+	}
+
+	return size;
+
+err:
+	clear_configuration(config);
+	return r;
+}
+
+/** \ingroup desc
+ * Get the USB device descriptor for a given device.
+ *
+ * This is a non-blocking function; the device descriptor is cached in memory.
+ *
+ * \param dev the device
+ * \param desc output location for the descriptor data
+ * \returns 0 on success or a LIBUSB_ERROR code on failure
+ */
+int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev,
+	struct libusb_device_descriptor *desc)
+{
+	unsigned char raw_desc[DEVICE_DESC_LENGTH];
+	int host_endian = 0;
+	int r;
+
+	usbi_dbg("");
+	r = usbi_backend->get_device_descriptor(dev, raw_desc, &host_endian);
+	if (r < 0)
+		return r;
+
+	memcpy((unsigned char *) desc, raw_desc, sizeof(raw_desc));
+	if (!host_endian) {
+		desc->bcdUSB = libusb_le16_to_cpu(desc->bcdUSB);
+		desc->idVendor = libusb_le16_to_cpu(desc->idVendor);
+		desc->idProduct = libusb_le16_to_cpu(desc->idProduct);
+		desc->bcdDevice = libusb_le16_to_cpu(desc->bcdDevice);
+	}
+	return 0;
+}
+
+/** \ingroup desc
+ * Get the USB configuration descriptor for the currently active configuration.
+ * This is a non-blocking function which does not involve any requests being
+ * sent to the device.
+ *
+ * \param dev a device
+ * \param config output location for the USB configuration descriptor. Only
+ * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
+ * after use.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state
+ * \returns another LIBUSB_ERROR code on error
+ * \see libusb_get_config_descriptor
+ */
+int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev,
+	struct libusb_config_descriptor **config)
+{
+	struct libusb_config_descriptor *_config = malloc(sizeof(*_config));
+	unsigned char tmp[8];
+	unsigned char *buf = NULL;
+	int host_endian = 0;
+	int r;
+
+	usbi_dbg("");
+	if (!_config)
+		return LIBUSB_ERROR_NO_MEM;
+
+	r = usbi_backend->get_active_config_descriptor(dev, tmp, sizeof(tmp),
+		&host_endian);
+	if (r < 0)
+		goto err;
+
+	usbi_parse_descriptor(tmp, "bbw", _config, host_endian);
+	buf = malloc(_config->wTotalLength);
+	if (!buf) {
+		r = LIBUSB_ERROR_NO_MEM;
+		goto err;
+	}
+
+	r = usbi_backend->get_active_config_descriptor(dev, buf,
+		_config->wTotalLength, &host_endian);
+	if (r < 0)
+		goto err;
+
+	r = parse_configuration(dev->ctx, _config, buf, host_endian);
+	if (r < 0) {
+		usbi_err(dev->ctx, "parse_configuration failed with error %d", r);
+		goto err;
+	} else if (r > 0) {
+		usbi_warn(dev->ctx, "descriptor data still left");
+	}
+
+	free(buf);
+	*config = _config;
+	return 0;
+
+err:
+	free(_config);
+	if (buf)
+		free(buf);
+	return r;
+}
+
+/** \ingroup desc
+ * Get a USB configuration descriptor based on its index.
+ * This is a non-blocking function which does not involve any requests being
+ * sent to the device.
+ *
+ * \param dev a device
+ * \param config_index the index of the configuration you wish to retrieve
+ * \param config output location for the USB configuration descriptor. Only
+ * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
+ * after use.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
+ * \returns another LIBUSB_ERROR code on error
+ * \see libusb_get_active_config_descriptor()
+ * \see libusb_get_config_descriptor_by_value()
+ */
+int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
+	uint8_t config_index, struct libusb_config_descriptor **config)
+{
+	struct libusb_config_descriptor *_config;
+	unsigned char tmp[8];
+	unsigned char *buf = NULL;
+	int host_endian = 0;
+	int r;
+
+	usbi_dbg("index %d", config_index);
+	if (config_index >= dev->num_configurations)
+		return LIBUSB_ERROR_NOT_FOUND;
+
+	_config = malloc(sizeof(*_config));
+	if (!_config)
+		return LIBUSB_ERROR_NO_MEM;
+
+	r = usbi_backend->get_config_descriptor(dev, config_index, tmp,
+		sizeof(tmp), &host_endian);
+	if (r < 0)
+		goto err;
+
+	usbi_parse_descriptor(tmp, "bbw", _config, host_endian);
+	buf = malloc(_config->wTotalLength);
+	if (!buf) {
+		r = LIBUSB_ERROR_NO_MEM;
+		goto err;
+	}
+
+	host_endian = 0;
+	r = usbi_backend->get_config_descriptor(dev, config_index, buf,
+		_config->wTotalLength, &host_endian);
+	if (r < 0)
+		goto err;
+
+	r = parse_configuration(dev->ctx, _config, buf, host_endian);
+	if (r < 0) {
+		usbi_err(dev->ctx, "parse_configuration failed with error %d", r);
+		goto err;
+	} else if (r > 0) {
+		usbi_warn(dev->ctx, "descriptor data still left");
+	}
+
+	free(buf);
+	*config = _config;
+	return 0;
+
+err:
+	free(_config);
+	if (buf)
+		free(buf);
+	return r;
+}
+
+/* iterate through all configurations, returning the index of the configuration
+ * matching a specific bConfigurationValue in the idx output parameter, or -1
+ * if the config was not found.
+ * returns 0 or a LIBUSB_ERROR code
+ */
+int usbi_get_config_index_by_value(struct libusb_device *dev,
+	uint8_t bConfigurationValue, int *idx)
+{
+	uint8_t i;
+
+	usbi_dbg("value %d", bConfigurationValue);
+	for (i = 0; i < dev->num_configurations; i++) {
+		unsigned char tmp[6];
+		int host_endian;
+		int r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp),
+			&host_endian);
+		if (r < 0)
+			return r;
+		if (tmp[5] == bConfigurationValue) {
+			*idx = i;
+			return 0;
+		}
+	}
+
+	*idx = -1;
+	return 0;
+}
+
+/** \ingroup desc
+ * Get a USB configuration descriptor with a specific bConfigurationValue.
+ * This is a non-blocking function which does not involve any requests being
+ * sent to the device.
+ *
+ * \param dev a device
+ * \param bConfigurationValue the bConfigurationValue of the configuration you
+ * wish to retrieve
+ * \param config output location for the USB configuration descriptor. Only
+ * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
+ * after use.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
+ * \returns another LIBUSB_ERROR code on error
+ * \see libusb_get_active_config_descriptor()
+ * \see libusb_get_config_descriptor()
+ */
+int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev,
+	uint8_t bConfigurationValue, struct libusb_config_descriptor **config)
+{
+	int idx;
+	int r = usbi_get_config_index_by_value(dev, bConfigurationValue, &idx);
+	if (r < 0)
+		return r;
+	else if (idx == -1)
+		return LIBUSB_ERROR_NOT_FOUND;
+	else
+		return libusb_get_config_descriptor(dev, (uint8_t) idx, config);
+}
+
+/** \ingroup desc
+ * Free a configuration descriptor obtained from
+ * libusb_get_active_config_descriptor() or libusb_get_config_descriptor().
+ * It is safe to call this function with a NULL config parameter, in which
+ * case the function simply returns.
+ *
+ * \param config the configuration descriptor to free
+ */
+void API_EXPORTED libusb_free_config_descriptor(
+	struct libusb_config_descriptor *config)
+{
+	if (!config)
+		return;
+
+	clear_configuration(config);
+	free(config);
+}
+
+/** \ingroup desc
+ * Retrieve a string descriptor in C style ASCII.
+ *
+ * Wrapper around libusb_get_string_descriptor(). Uses the first language
+ * supported by the device.
+ *
+ * \param dev a device handle
+ * \param desc_index the index of the descriptor to retrieve
+ * \param data output buffer for ASCII string descriptor
+ * \param length size of data buffer
+ * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure
+ */
+int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev,
+	uint8_t desc_index, unsigned char *data, int length)
+{
+	unsigned char tbuf[255]; /* Some devices choke on size > 255 */
+	int r, si, di;
+	uint16_t langid;
+
+	/* Asking for the zero'th index is special - it returns a string
+	 * descriptor that contains all the language IDs supported by the
+	 * device. Typically there aren't many - often only one. 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;
+}
+
diff --git a/libusb/io.c b/libusb/io.c
new file mode 100644
index 0000000..e9bd312
--- /dev/null
+++ b/libusb/io.c
@@ -0,0 +1,2454 @@
+/*
+ * I/O functions for libusb
+ * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef USBI_TIMERFD_AVAILABLE
+#include <sys/timerfd.h>
+#endif
+
+#include "libusbi.h"
+
+/**
+ * \page io Synchronous and asynchronous device I/O
+ *
+ * \section intro Introduction
+ *
+ * If you're using libusb in your application, you're probably wanting to
+ * perform I/O with devices - you want to perform USB data transfers.
+ *
+ * libusb offers two separate interfaces for device I/O. This page aims to
+ * introduce the two in order to help you decide which one is more suitable
+ * for your application. You can also choose to use both interfaces in your
+ * application by considering each transfer on a case-by-case basis.
+ *
+ * Once you have read through the following discussion, you should consult the
+ * detailed API documentation pages for the details:
+ * - \ref syncio
+ * - \ref asyncio
+ *
+ * \section theory Transfers at a logical level
+ *
+ * At a logical level, USB transfers typically happen in two parts. For
+ * example, when reading data from a endpoint:
+ * -# A request for data is sent to the device
+ * -# Some time later, the incoming data is received by the host
+ *
+ * or when writing data to an endpoint:
+ *
+ * -# The data is sent to the device
+ * -# Some time later, the host receives acknowledgement from the device that
+ *    the data has been transferred.
+ *
+ * There may be an indefinite delay between the two steps. Consider a
+ * fictional USB input device with a button that the user can press. In order
+ * to determine when the button is pressed, you would likely submit a request
+ * to read data on a bulk or interrupt endpoint and wait for data to arrive.
+ * Data will arrive when the button is pressed by the user, which is
+ * potentially hours later.
+ *
+ * libusb offers both a synchronous and an asynchronous interface to performing
+ * USB transfers. The main difference is that the synchronous interface
+ * combines both steps indicated above into a single function call, whereas
+ * the asynchronous interface separates them.
+ *
+ * \section sync The synchronous interface
+ *
+ * The synchronous I/O interface allows you to perform a USB transfer with
+ * a single function call. When the function call returns, the transfer has
+ * completed and you can parse the results.
+ *
+ * If you have used the libusb-0.1 before, this I/O style will seem familar to
+ * you. libusb-0.1 only offered a synchronous interface.
+ *
+ * In our input device example, to read button presses you might write code
+ * in the following style:
+\code
+unsigned char data[4];
+int actual_length;
+int r = libusb_bulk_transfer(handle, 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;
+
+#ifdef USBI_TIMERFD_AVAILABLE
+	ctx->timerfd = timerfd_create(usbi_backend->get_timerfd_clockid(),
+		TFD_NONBLOCK);
+	if (ctx->timerfd >= 0) {
+		usbi_dbg("using timerfd for timeouts");
+		r = usbi_add_pollfd(ctx, ctx->timerfd, POLLIN);
+		if (r < 0) {
+			usbi_remove_pollfd(ctx, ctx->ctrl_pipe[0]);
+			close(ctx->timerfd);
+			goto err_close_pipe;
+		}
+	} else {
+		usbi_dbg("timerfd not available (code %d error %d)", ctx->timerfd, errno);
+		ctx->timerfd = -1;
+	}
+#endif
+
+	return 0;
+
+err_close_pipe:
+	usbi_close(ctx->ctrl_pipe[0]);
+	usbi_close(ctx->ctrl_pipe[1]);
+err:
+	usbi_mutex_destroy(&ctx->flying_transfers_lock);
+	usbi_mutex_destroy(&ctx->pollfds_lock);
+	usbi_mutex_destroy(&ctx->pollfd_modify_lock);
+	usbi_mutex_destroy(&ctx->events_lock);
+	usbi_mutex_destroy(&ctx->event_waiters_lock);
+	usbi_cond_destroy(&ctx->event_waiters_cond);
+	return r;
+}
+
+void usbi_io_exit(struct libusb_context *ctx)
+{
+	usbi_remove_pollfd(ctx, ctx->ctrl_pipe[0]);
+	usbi_close(ctx->ctrl_pipe[0]);
+	usbi_close(ctx->ctrl_pipe[1]);
+#ifdef USBI_TIMERFD_AVAILABLE
+	if (usbi_using_timerfd(ctx)) {
+		usbi_remove_pollfd(ctx, ctx->timerfd);
+		close(ctx->timerfd);
+	}
+#endif
+	usbi_mutex_destroy(&ctx->flying_transfers_lock);
+	usbi_mutex_destroy(&ctx->pollfds_lock);
+	usbi_mutex_destroy(&ctx->pollfd_modify_lock);
+	usbi_mutex_destroy(&ctx->events_lock);
+	usbi_mutex_destroy(&ctx->event_waiters_lock);
+	usbi_cond_destroy(&ctx->event_waiters_cond);
+}
+
+static int calculate_timeout(struct usbi_transfer *transfer)
+{
+	int r;
+	struct timespec current_time;
+	unsigned int timeout =
+		USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout;
+
+	if (!timeout)
+		return 0;
+
+	r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &current_time);
+	if (r < 0) {
+		usbi_err(ITRANSFER_CTX(transfer),
+			"failed to read monotonic clock, errno=%d", errno);
+		return r;
+	}
+
+	current_time.tv_sec += timeout / 1000;
+	current_time.tv_nsec += (timeout % 1000) * 1000000;
+
+	if (current_time.tv_nsec > 1000000000) {
+		current_time.tv_nsec -= 1000000000;
+		current_time.tv_sec++;
+	}
+
+	TIMESPEC_TO_TIMEVAL(&transfer->timeout, &current_time);
+	return 0;
+}
+
+/* add a transfer to the (timeout-sorted) active transfers list.
+ * returns 1 if the transfer has a timeout and it is the timeout next to
+ * expire */
+static int add_to_flying_list(struct usbi_transfer *transfer)
+{
+	struct usbi_transfer *cur;
+	struct timeval *timeout = &transfer->timeout;
+	struct libusb_context *ctx = ITRANSFER_CTX(transfer);
+	int r = 0;
+	int first = 1;
+
+	usbi_mutex_lock(&ctx->flying_transfers_lock);
+
+	/* if we have no other flying transfers, start the list with this one */
+	if (list_empty(&ctx->flying_transfers)) {
+		list_add(&transfer->list, &ctx->flying_transfers);
+		if (timerisset(timeout))
+			r = 1;
+		goto out;
+	}
+
+	/* if we have infinite timeout, append to end of list */
+	if (!timerisset(timeout)) {
+		list_add_tail(&transfer->list, &ctx->flying_transfers);
+		goto out;
+	}
+
+	/* otherwise, find appropriate place in list */
+	list_for_each_entry(cur, &ctx->flying_transfers, list, struct usbi_transfer) {
+		/* find first timeout that occurs after the transfer in question */
+		struct timeval *cur_tv = &cur->timeout;
+
+		if (!timerisset(cur_tv) || (cur_tv->tv_sec > timeout->tv_sec) ||
+				(cur_tv->tv_sec == timeout->tv_sec &&
+					cur_tv->tv_usec > timeout->tv_usec)) {
+			list_add_tail(&transfer->list, &cur->list);
+			r = first;
+			goto out;
+		}
+		first = 0;
+	}
+
+	/* otherwise we need to be inserted at the end */
+	list_add_tail(&transfer->list, &ctx->flying_transfers);
+out:
+	usbi_mutex_unlock(&ctx->flying_transfers_lock);
+	return r;
+}
+
+/** \ingroup asyncio
+ * Allocate a libusb transfer with a specified number of isochronous packet
+ * descriptors. The returned transfer is pre-initialized for you. When the new
+ * transfer is no longer needed, it should be freed with
+ * libusb_free_transfer().
+ *
+ * Transfers intended for non-isochronous endpoints (e.g. control, bulk,
+ * interrupt) should specify an iso_packets count of zero.
+ *
+ * For transfers intended for isochronous endpoints, specify an appropriate
+ * number of packet descriptors to be allocated as part of the transfer.
+ * The returned transfer is not specially initialized for isochronous I/O;
+ * you are still required to set the
+ * \ref libusb_transfer::num_iso_packets "num_iso_packets" and
+ * \ref libusb_transfer::type "type" fields accordingly.
+ *
+ * It is safe to allocate a transfer with some isochronous packets and then
+ * use it on a non-isochronous endpoint. If you do this, ensure that at time
+ * of submission, num_iso_packets is 0 and that type is set appropriately.
+ *
+ * \param iso_packets number of isochronous packet descriptors to allocate
+ * \returns a newly allocated transfer, or NULL on error
+ */
+DEFAULT_VISIBILITY
+struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(
+	int iso_packets)
+{
+	size_t os_alloc_size = usbi_backend->transfer_priv_size
+		+ (usbi_backend->add_iso_packet_size * iso_packets);
+	size_t alloc_size = sizeof(struct usbi_transfer)
+		+ sizeof(struct libusb_transfer)
+		+ (sizeof(struct libusb_iso_packet_descriptor) * iso_packets)
+		+ os_alloc_size;
+	struct usbi_transfer *itransfer = malloc(alloc_size);
+	if (!itransfer)
+		return NULL;
+
+	memset(itransfer, 0, alloc_size);
+	itransfer->num_iso_packets = iso_packets;
+	usbi_mutex_init(&itransfer->lock, NULL);
+	return USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+}
+
+/** \ingroup asyncio
+ * Free a transfer structure. This should be called for all transfers
+ * allocated with libusb_alloc_transfer().
+ *
+ * If the \ref libusb_transfer_flags::LIBUSB_TRANSFER_FREE_BUFFER
+ * "LIBUSB_TRANSFER_FREE_BUFFER" flag is set and the transfer buffer is
+ * non-NULL, this function will also free the transfer buffer using the
+ * standard system memory allocator (e.g. free()).
+ *
+ * It is legal to call this function with a NULL transfer. In this case,
+ * the function will simply return safely.
+ *
+ * It is not legal to free an active transfer (one which has been submitted
+ * and has not yet completed).
+ *
+ * \param transfer the transfer to free
+ */
+void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer)
+{
+	struct usbi_transfer *itransfer;
+	if (!transfer)
+		return;
+
+	if (transfer->flags & LIBUSB_TRANSFER_FREE_BUFFER && transfer->buffer)
+		free(transfer->buffer);
+
+	itransfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
+	usbi_mutex_destroy(&itransfer->lock);
+	free(itransfer);
+}
+
+/** \ingroup asyncio
+ * Submit a transfer. This function will fire off the USB transfer and then
+ * return immediately.
+ *
+ * \param transfer the transfer to submit
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns LIBUSB_ERROR_BUSY if the transfer has already been submitted.
+ * \returns 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;
+
+	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:
+	usbi_mutex_unlock(&itransfer->lock);
+	return r;
+}
+
+/** \ingroup asyncio
+ * Asynchronously cancel a previously submitted transfer.
+ * This function returns immediately, but this does not indicate cancellation
+ * is complete. Your callback function will be invoked at some later time
+ * with a transfer status of
+ * \ref libusb_transfer_status::LIBUSB_TRANSFER_CANCELLED
+ * "LIBUSB_TRANSFER_CANCELLED."
+ *
+ * \param transfer the transfer to cancel
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the transfer is already complete or
+ * cancelled.
+ * \returns a LIBUSB_ERROR code on failure
+ */
+int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer)
+{
+	struct usbi_transfer *itransfer =
+		LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
+	int r;
+
+	usbi_dbg("");
+	usbi_mutex_lock(&itransfer->lock);
+	r = usbi_backend->cancel_transfer(itransfer);
+	if (r < 0) {
+		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);
+	usbi_mutex_unlock(&ctx->flying_transfers_lock);
+
+	if (usbi_using_timerfd(ctx)) {
+		if (r < 0)
+			return r;
+		r = disarm_timerfd(ctx);
+		if (r < 0)
+			return r;
+	}
+
+	if (status == LIBUSB_TRANSFER_COMPLETED
+			&& transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
+		int rqlen = transfer->length;
+		if (transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL)
+			rqlen -= LIBUSB_CONTROL_SETUP_SIZE;
+		if (rqlen != itransfer->transferred) {
+			usbi_dbg("interpreting short transfer as error");
+			status = LIBUSB_TRANSFER_ERROR;
+		}
+	}
+
+	flags = transfer->flags;
+	transfer->status = status;
+	transfer->actual_length = itransfer->transferred;
+	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;
+	if (timeout.tv_nsec > 1000000000) {
+		timeout.tv_nsec -= 1000000000;
+		timeout.tv_sec++;
+	}
+
+	r = usbi_cond_timedwait(&ctx->event_waiters_cond,
+		&ctx->event_waiters_lock, &timeout);
+	return (r == ETIMEDOUT);
+}
+
+static void handle_timeout(struct usbi_transfer *itransfer)
+{
+	struct libusb_transfer *transfer =
+		USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+	int r;
+
+	itransfer->flags |= USBI_TRANSFER_TIMED_OUT;
+	r = libusb_cancel_transfer(transfer);
+	if (r < 0)
+		usbi_warn(TRANSFER_CTX(transfer),
+			"async cancel failed %d errno=%d", r, errno);
+}
+
+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--;
+		}
+	}
+
+#ifdef USBI_TIMERFD_AVAILABLE
+	/* on timerfd configurations, fds[1] is the timerfd */
+	if (usbi_using_timerfd(ctx) && fds[1].revents) {
+		/* timerfd indicates that a timeout has expired */
+		int ret;
+		usbi_dbg("timerfd triggered");
+
+		ret = handle_timerfd_trigger(ctx);
+		if (ret < 0) {
+			/* return error code */
+			r = ret;
+			goto handled;
+		} else if (r == 1) {
+			/* no more active file descriptors, nothing more to do */
+			r = 0;
+			goto handled;
+		} else {
+			/* more events pending...
+			 * prevent OS backend from trying to handle events on timerfd */
+			fds[1].revents = 0;
+			r--;
+		}
+	}
+#endif
+
+	r = usbi_backend->handle_events(ctx, fds, nfds, r);
+	if (r)
+		usbi_err(ctx, "backend handle_events failed with error %d", r);
+
+handled:
+	free(fds);
+	return r;
+}
+
+/* returns the smallest of:
+ *  1. timeout of next URB
+ *  2. user-supplied timeout
+ * returns 1 if there is an already-expired timeout, otherwise returns 0
+ * and populates out
+ */
+static int get_next_timeout(libusb_context *ctx, struct timeval *tv,
+	struct timeval *out)
+{
+	struct timeval timeout;
+	int r = libusb_get_next_timeout(ctx, &timeout);
+	if (r) {
+		/* timeout already expired? */
+		if (!timerisset(&timeout))
+			return 1;
+
+		/* choose the smallest of next URB timeout or user specified timeout */
+		if (timercmp(&timeout, tv, <))
+			*out = timeout;
+		else
+			*out = *tv;
+	} else {
+		*out = *tv;
+	}
+	return 0;
+}
+
+/** \ingroup poll
+ * Handle any pending events.
+ *
+ * libusb determines "pending events" by checking if any timeouts have expired
+ * and by checking the set of file descriptors for activity.
+ *
+ * If a zero timeval is passed, this function will handle any already-pending
+ * events and then immediately return in non-blocking style.
+ *
+ * If a non-zero timeval is passed and no events are currently pending, this
+ * function will block waiting for events to handle up until the specified
+ * timeout. If an event arrives or a signal is raised, this function will
+ * return early.
+ *
+ * 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);
+	}
+
+}
diff --git a/libusb/libusb-1.0.def b/libusb/libusb-1.0.def
new file mode 100644
index 0000000..1d6a5d2
--- /dev/null
+++ b/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
diff --git a/libusb/libusb-1.0.rc b/libusb/libusb-1.0.rc
new file mode 100644
index 0000000..a59a430
--- /dev/null
+++ b/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
diff --git a/libusb/libusb.h b/libusb/libusb.h
new file mode 100644
index 0000000..58b406f
--- /dev/null
+++ b/libusb/libusb.h
@@ -0,0 +1,1443 @@
+/*
+ * Public libusb header file
+ * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBUSB_H
+#define LIBUSB_H
+
+#ifdef _MSC_VER
+/* on MS environments, the inline keyword is available in C++ only */
+#define inline __inline
+/* ssize_t is also not available (copy/paste from MinGW) */
+#ifndef _SSIZE_T_DEFINED
+#define _SSIZE_T_DEFINED
+#undef ssize_t
+#ifdef _WIN64
+  typedef __int64 ssize_t;
+#else
+  typedef int ssize_t;
+#endif /* _WIN64 */
+#endif /* _SSIZE_T_DEFINED */
+#endif /* _MSC_VER */
+
+/* stdint.h is also not usually available on MS */
+#if defined(_MSC_VER) && (_MSC_VER < 1600) && (!defined(_STDINT)) && (!defined(_STDINT_H))
+typedef unsigned __int8   uint8_t;
+typedef unsigned __int16  uint16_t;
+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,
+};
+
+/* Descriptor sizes per descriptor type */
+#define LIBUSB_DT_DEVICE_SIZE			18
+#define LIBUSB_DT_CONFIG_SIZE			9
+#define LIBUSB_DT_INTERFACE_SIZE		9
+#define LIBUSB_DT_ENDPOINT_SIZE		7
+#define LIBUSB_DT_ENDPOINT_AUDIO_SIZE	9	/* Audio extension */
+#define LIBUSB_DT_HUB_NONVAR_SIZE		7
+
+#define LIBUSB_ENDPOINT_ADDRESS_MASK	0x0f    /* in bEndpointAddress */
+#define LIBUSB_ENDPOINT_DIR_MASK		0x80
+
+/** \ingroup desc
+ * Endpoint direction. Values for bit 7 of the
+ * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme.
+ */
+enum libusb_endpoint_direction {
+	/** In: device-to-host */
+	LIBUSB_ENDPOINT_IN = 0x80,
+
+	/** Out: host-to-device */
+	LIBUSB_ENDPOINT_OUT = 0x00
+};
+
+#define LIBUSB_TRANSFER_TYPE_MASK			0x03    /* in bmAttributes */
+
+/** \ingroup desc
+ * Endpoint transfer type. Values for bits 0:1 of the
+ * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field.
+ */
+enum libusb_transfer_type {
+	/** Control endpoint */
+	LIBUSB_TRANSFER_TYPE_CONTROL = 0,
+
+	/** Isochronous endpoint */
+	LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1,
+
+	/** Bulk endpoint */
+	LIBUSB_TRANSFER_TYPE_BULK = 2,
+
+	/** Interrupt endpoint */
+	LIBUSB_TRANSFER_TYPE_INTERRUPT = 3
+};
+
+/** \ingroup misc
+ * Standard requests, as defined in table 9-3 of the USB2 specifications */
+enum libusb_standard_request {
+	/** Request status of the specific recipient */
+	LIBUSB_REQUEST_GET_STATUS = 0x00,
+
+	/** Clear or disable a specific feature */
+	LIBUSB_REQUEST_CLEAR_FEATURE = 0x01,
+
+	/* 0x02 is reserved */
+
+	/** Set or enable a specific feature */
+	LIBUSB_REQUEST_SET_FEATURE = 0x03,
+
+	/* 0x04 is reserved */
+
+	/** Set device address for all future accesses */
+	LIBUSB_REQUEST_SET_ADDRESS = 0x05,
+
+	/** Get the specified descriptor */
+	LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06,
+
+	/** Used to update existing descriptors or add new descriptors */
+	LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07,
+
+	/** Get the current device configuration value */
+	LIBUSB_REQUEST_GET_CONFIGURATION = 0x08,
+
+	/** Set device configuration */
+	LIBUSB_REQUEST_SET_CONFIGURATION = 0x09,
+
+	/** Return the selected alternate setting for the specified interface */
+	LIBUSB_REQUEST_GET_INTERFACE = 0x0A,
+
+	/** Select an alternate interface for the specified interface */
+	LIBUSB_REQUEST_SET_INTERFACE = 0x0B,
+
+	/** Set then report an endpoint's synchronization frame */
+	LIBUSB_REQUEST_SYNCH_FRAME = 0x0C,
+};
+
+/** \ingroup misc
+ * Request type bits of the
+ * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control
+ * transfers. */
+enum libusb_request_type {
+	/** Standard */
+	LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5),
+
+	/** Class */
+	LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5),
+
+	/** Vendor */
+	LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5),
+
+	/** Reserved */
+	LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5)
+};
+
+/** \ingroup misc
+ * Recipient bits of the
+ * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control
+ * transfers. Values 4 through 31 are reserved. */
+enum libusb_request_recipient {
+	/** Device */
+	LIBUSB_RECIPIENT_DEVICE = 0x00,
+
+	/** Interface */
+	LIBUSB_RECIPIENT_INTERFACE = 0x01,
+
+	/** Endpoint */
+	LIBUSB_RECIPIENT_ENDPOINT = 0x02,
+
+	/** Other */
+	LIBUSB_RECIPIENT_OTHER = 0x03,
+};
+
+#define LIBUSB_ISO_SYNC_TYPE_MASK		0x0C
+
+/** \ingroup desc
+ * Synchronization type for isochronous endpoints. Values for bits 2:3 of the
+ * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in
+ * libusb_endpoint_descriptor.
+ */
+enum libusb_iso_sync_type {
+	/** No synchronization */
+	LIBUSB_ISO_SYNC_TYPE_NONE = 0,
+
+	/** Asynchronous */
+	LIBUSB_ISO_SYNC_TYPE_ASYNC = 1,
+
+	/** Adaptive */
+	LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2,
+
+	/** Synchronous */
+	LIBUSB_ISO_SYNC_TYPE_SYNC = 3
+};
+
+#define LIBUSB_ISO_USAGE_TYPE_MASK 0x30
+
+/** \ingroup desc
+ * Usage type for isochronous endpoints. Values for bits 4:5 of the
+ * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in
+ * libusb_endpoint_descriptor.
+ */
+enum libusb_iso_usage_type {
+	/** Data endpoint */
+	LIBUSB_ISO_USAGE_TYPE_DATA = 0,
+
+	/** Feedback endpoint */
+	LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1,
+
+	/** Implicit feedback Data endpoint */
+	LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2,
+};
+
+/** \ingroup desc
+ * A structure representing the standard USB device descriptor. This
+ * descriptor is documented in section 9.6.1 of the USB 2.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_device_descriptor {
+	/** Size of this descriptor (in bytes) */
+	uint8_t  bLength;
+
+	/** Descriptor type. Will have value
+	 * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this
+	 * context. */
+	uint8_t  bDescriptorType;
+
+	/** USB specification release number in binary-coded decimal. A value of
+	 * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */
+	uint16_t bcdUSB;
+
+	/** USB-IF class code for the device. See \ref libusb_class_code. */
+	uint8_t  bDeviceClass;
+
+	/** USB-IF subclass code for the device, qualified by the bDeviceClass
+	 * value */
+	uint8_t  bDeviceSubClass;
+
+	/** USB-IF protocol code for the device, qualified by the bDeviceClass and
+	 * bDeviceSubClass values */
+	uint8_t  bDeviceProtocol;
+
+	/** Maximum packet size for endpoint 0 */
+	uint8_t  bMaxPacketSize0;
+
+	/** USB-IF vendor ID */
+	uint16_t idVendor;
+
+	/** USB-IF product ID */
+	uint16_t idProduct;
+
+	/** Device release number in binary-coded decimal */
+	uint16_t bcdDevice;
+
+	/** Index of string descriptor describing manufacturer */
+	uint8_t  iManufacturer;
+
+	/** Index of string descriptor describing product */
+	uint8_t  iProduct;
+
+	/** Index of string descriptor containing device serial number */
+	uint8_t  iSerialNumber;
+
+	/** Number of possible configurations */
+	uint8_t  bNumConfigurations;
+};
+
+/** \ingroup desc
+ * A structure representing the standard USB endpoint descriptor. This
+ * descriptor is documented in section 9.6.3 of the USB 2.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_endpoint_descriptor {
+	/** Size of this descriptor (in bytes) */
+	uint8_t  bLength;
+
+	/** Descriptor type. Will have value
+	 * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in
+	 * this context. */
+	uint8_t  bDescriptorType;
+
+	/** The address of the endpoint described by this descriptor. Bits 0:3 are
+	 * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction,
+	 * see \ref libusb_endpoint_direction.
+	 */
+	uint8_t  bEndpointAddress;
+
+	/** Attributes which apply to the endpoint when it is configured using
+	 * the bConfigurationValue. Bits 0:1 determine the transfer type and
+	 * correspond to \ref libusb_transfer_type. Bits 2:3 are only used for
+	 * isochronous endpoints and correspond to \ref libusb_iso_sync_type.
+	 * Bits 4:5 are also only used for isochronous endpoints and correspond to
+	 * \ref libusb_iso_usage_type. Bits 6:7 are reserved.
+	 */
+	uint8_t  bmAttributes;
+
+	/** Maximum packet size this endpoint is capable of sending/receiving. */
+	uint16_t wMaxPacketSize;
+
+	/** Interval for polling endpoint for data transfers. */
+	uint8_t  bInterval;
+
+	/** For audio devices only: the rate at which synchronization feedback
+	 * is provided. */
+	uint8_t  bRefresh;
+
+	/** For audio devices only: the address if the synch endpoint */
+	uint8_t  bSynchAddress;
+
+	/** Extra descriptors. If libusb encounters unknown endpoint descriptors,
+	 * it will store them here, should you wish to parse them. */
+	const unsigned char *extra;
+
+	/** Length of the extra descriptors, in bytes. */
+	int extra_length;
+};
+
+/** \ingroup desc
+ * A structure representing the standard USB interface descriptor. This
+ * descriptor is documented in section 9.6.5 of the USB 2.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_interface_descriptor {
+	/** Size of this descriptor (in bytes) */
+	uint8_t  bLength;
+
+	/** Descriptor type. Will have value
+	 * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE
+	 * in this context. */
+	uint8_t  bDescriptorType;
+
+	/** Number of this interface */
+	uint8_t  bInterfaceNumber;
+
+	/** Value used to select this alternate setting for this interface */
+	uint8_t  bAlternateSetting;
+
+	/** Number of endpoints used by this interface (excluding the control
+	 * endpoint). */
+	uint8_t  bNumEndpoints;
+
+	/** USB-IF class code for this interface. See \ref libusb_class_code. */
+	uint8_t  bInterfaceClass;
+
+	/** USB-IF subclass code for this interface, qualified by the
+	 * bInterfaceClass value */
+	uint8_t  bInterfaceSubClass;
+
+	/** USB-IF protocol code for this interface, qualified by the
+	 * bInterfaceClass and bInterfaceSubClass values */
+	uint8_t  bInterfaceProtocol;
+
+	/** Index of string descriptor describing this interface */
+	uint8_t  iInterface;
+
+	/** Array of endpoint descriptors. This length of this array is determined
+	 * by the bNumEndpoints field. */
+	const struct libusb_endpoint_descriptor *endpoint;
+
+	/** Extra descriptors. If libusb encounters unknown interface descriptors,
+	 * it will store them here, should you wish to parse them. */
+	const unsigned char *extra;
+
+	/** Length of the extra descriptors, in bytes. */
+	int extra_length;
+};
+
+/** \ingroup desc
+ * A collection of alternate settings for a particular USB interface.
+ */
+struct libusb_interface {
+	/** Array of interface descriptors. The length of this array is determined
+	 * by the num_altsetting field. */
+	const struct libusb_interface_descriptor *altsetting;
+
+	/** The number of alternate settings that belong to this interface */
+	int num_altsetting;
+};
+
+/** \ingroup desc
+ * A structure representing the standard USB configuration descriptor. This
+ * descriptor is documented in section 9.6.3 of the USB 2.0 specification.
+ * All multiple-byte fields are represented in host-endian format.
+ */
+struct libusb_config_descriptor {
+	/** Size of this descriptor (in bytes) */
+	uint8_t  bLength;
+
+	/** Descriptor type. Will have value
+	 * \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG
+	 * in this context. */
+	uint8_t  bDescriptorType;
+
+	/** Total length of data returned for this configuration */
+	uint16_t wTotalLength;
+
+	/** Number of interfaces supported by this configuration */
+	uint8_t  bNumInterfaces;
+
+	/** Identifier value for this configuration */
+	uint8_t  bConfigurationValue;
+
+	/** Index of string descriptor describing this configuration */
+	uint8_t  iConfiguration;
+
+	/** Configuration characteristics */
+	uint8_t  bmAttributes;
+
+	/** Maximum power consumption of the USB device from this bus in this
+	 * configuration when the device is fully opreation. Expressed in units
+	 * of 2 mA. */
+	uint8_t  MaxPower;
+
+	/** Array of interfaces supported by this configuration. The length of
+	 * this array is determined by the bNumInterfaces field. */
+	const struct libusb_interface *interface;
+
+	/** Extra descriptors. If libusb encounters unknown configuration
+	 * descriptors, it will store them here, should you wish to parse them. */
+	const unsigned char *extra;
+
+	/** Length of the extra descriptors, in bytes. */
+	int extra_length;
+};
+
+/** \ingroup asyncio
+ * Setup packet for control transfers. */
+struct libusb_control_setup {
+	/** Request type. Bits 0:4 determine recipient, see
+	 * \ref libusb_request_recipient. Bits 5:6 determine type, see
+	 * \ref libusb_request_type. Bit 7 determines data transfer direction, see
+	 * \ref libusb_endpoint_direction.
+	 */
+	uint8_t  bmRequestType;
+
+	/** Request. If the type bits of bmRequestType are equal to
+	 * \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD
+	 * "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to
+	 * \ref libusb_standard_request. For other cases, use of this field is
+	 * application-specific. */
+	uint8_t  bRequest;
+
+	/** Value. Varies according to request */
+	uint16_t wValue;
+
+	/** Index. Varies according to request, typically used to pass an index
+	 * or offset */
+	uint16_t wIndex;
+
+	/** Number of bytes to transfer */
+	uint16_t wLength;
+};
+
+#define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup))
+
+/* libusb */
+
+struct libusb_context;
+struct libusb_device;
+struct libusb_device_handle;
+
+/** \ingroup lib
+ * Structure 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_device_ref() and
+ * libusb_device_unref(), and are freed when the reference count reaches 0.
+ * New devices presented by libusb_get_device_list() have a reference count of
+ * 1, and libusb_free_device_list() can optionally decrease the reference count
+ * on all devices in the list. libusb_open() adds another reference which is
+ * later destroyed by libusb_close().
+ */
+typedef struct libusb_device libusb_device;
+
+
+/** \ingroup dev
+ * Structure representing a handle on a USB device. This is an opaque type for
+ * which you are only ever provided with a pointer, usually originating from
+ * libusb_open().
+ *
+ * A device handle is used to perform I/O and other operations. When finished
+ * with a device handle, you should call libusb_close().
+ */
+typedef struct libusb_device_handle libusb_device_handle;
+
+/** \ingroup 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 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.
+ */
+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()
+	   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,
+};
+
+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);
+
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
new file mode 100644
index 0000000..976be0d
--- /dev/null
+++ b/libusb/libusbi.h
@@ -0,0 +1,935 @@
+/*
+ * 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;
+
+	/* this is a list of in-flight transfer handles, sorted by timeout
+	 * expiration. URBs to timeout the soonest are placed at the beginning of
+	 * the list, URBs that will time out later are placed after, and urbs with
+	 * infinite timeout are always placed at the very end. */
+	struct list_head flying_transfers;
+	usbi_mutex_t flying_transfers_lock;
+
+	/* list of poll fds */
+	struct list_head pollfds;
+	usbi_mutex_t pollfds_lock;
+
+	/* a counter that is set when we want to interrupt event handling, in order
+	 * to modify the poll fd set. and a lock to protect it. */
+	unsigned int pollfd_modify;
+	usbi_mutex_t pollfd_modify_lock;
+
+	/* user callbacks for pollfd changes */
+	libusb_pollfd_added_cb fd_added_cb;
+	libusb_pollfd_removed_cb fd_removed_cb;
+	void *fd_cb_user_data;
+
+	/* ensures that only one thread is handling events at any one time */
+	usbi_mutex_t events_lock;
+
+	/* used to see if there is an active thread doing event handling */
+	int event_handler_active;
+
+	/* used to wait for event completion in threads other than the one that is
+	 * event handling */
+	usbi_mutex_t event_waiters_lock;
+	usbi_cond_t event_waiters_cond;
+
+#ifdef USBI_TIMERFD_AVAILABLE
+	/* used for timeout handling, if supported by OS.
+	 * this timerfd is maintained to trigger on the next pending timeout */
+	int timerfd;
+#endif
+};
+
+#ifdef USBI_TIMERFD_AVAILABLE
+#define usbi_using_timerfd(ctx) ((ctx)->timerfd >= 0)
+#else
+#define usbi_using_timerfd(ctx) (0)
+#endif
+
+struct libusb_device {
+	/* lock protects refcnt, everything else is finalized at initialization
+	 * time */
+	usbi_mutex_t lock;
+	int refcnt;
+
+	struct libusb_context *ctx;
+
+	uint8_t bus_number;
+	uint8_t device_address;
+	uint8_t num_configurations;
+	enum libusb_speed speed;
+
+	struct list_head list;
+	unsigned long session_data;
+	unsigned char os_priv[0];
+};
+
+struct libusb_device_handle {
+	/* lock protects claimed_interfaces */
+	usbi_mutex_t lock;
+	unsigned long claimed_interfaces;
+
+	struct list_head list;
+	struct libusb_device *dev;
+	unsigned char os_priv[0];
+};
+
+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,
+};
+
+#define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \
+	((struct libusb_transfer *)(((unsigned char *)(transfer)) \
+		+ sizeof(struct usbi_transfer)))
+#define LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer) \
+	((struct usbi_transfer *)(((unsigned char *)(transfer)) \
+		- sizeof(struct usbi_transfer)))
+
+static inline void *usbi_transfer_get_os_priv(struct usbi_transfer *transfer)
+{
+	return ((unsigned char *)transfer) + sizeof(struct usbi_transfer)
+		+ sizeof(struct libusb_transfer)
+		+ (transfer->num_iso_packets
+			* sizeof(struct libusb_iso_packet_descriptor));
+}
+
+/* bus structures */
+
+/* All standard descriptors have these 2 fields in common */
+struct usb_descriptor_header {
+	uint8_t  bLength;
+	uint8_t  bDescriptorType;
+};
+
+/* shared data and functions */
+
+int usbi_io_init(struct libusb_context *ctx);
+void usbi_io_exit(struct libusb_context *ctx);
+
+struct libusb_device *usbi_alloc_device(struct libusb_context *ctx,
+	unsigned long session_id);
+struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx,
+	unsigned long session_id);
+int usbi_sanitize_device(struct libusb_device *dev);
+void usbi_handle_disconnect(struct libusb_device_handle *handle);
+
+int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
+	enum libusb_transfer_status status);
+int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer);
+
+int usbi_parse_descriptor(unsigned char *source, const char *descriptor,
+	void *dest, int host_endian);
+int usbi_get_config_index_by_value(struct libusb_device *dev,
+	uint8_t bConfigurationValue, int *idx);
+
+/* polling */
+
+struct usbi_pollfd {
+	/* must come first */
+	struct libusb_pollfd pollfd;
+
+	struct list_head list;
+};
+
+int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events);
+void usbi_remove_pollfd(struct libusb_context *ctx, int fd);
+void usbi_fd_notification(struct libusb_context *ctx);
+
+/* device discovery */
+
+/* we traverse usbfs without knowing how many devices we are going to find.
+ * so we create this discovered_devs model which is similar to a linked-list
+ * which grows when required. it can be freed once discovery has completed,
+ * eliminating the need for a list node in the libusb_device structure
+ * itself. */
+struct discovered_devs {
+	size_t len;
+	size_t capacity;
+	struct libusb_device *devices[0];
+};
+
+struct discovered_devs *discovered_devs_append(
+	struct discovered_devs *discdevs, struct libusb_device *dev);
+
+/* OS abstraction */
+
+/* This is the interface that OS backends need to implement.
+ * All fields are mandatory, except ones explicitly noted as optional. */
+struct usbi_os_backend {
+	/* A human-readable name for your backend, e.g. "Linux usbfs" */
+	const char *name;
+
+	/* Perform initialization of your backend. You might use this function
+	 * to determine specific capabilities of the system, allocate required
+	 * data structures for later, etc.
+	 *
+	 * This function is called when a libusb user initializes the library
+	 * prior to use.
+	 *
+	 * Return 0 on success, or a LIBUSB_ERROR code on failure.
+	 */
+	int (*init)(struct libusb_context *ctx);
+
+	/* Deinitialization. Optional. This function should destroy anything
+	 * that was set up by init.
+	 *
+	 * This function is called when the user deinitializes the library.
+	 */
+	void (*exit)(void);
+
+	/* Enumerate all the USB devices on the system, returning them in a list
+	 * of discovered devices.
+	 *
+	 * Your implementation should enumerate all devices on the system,
+	 * regardless of whether they have been seen before or not.
+	 *
+	 * When you have found a device, compute a session ID for it. The session
+	 * ID should uniquely represent that particular device for that particular
+	 * connection session since boot (i.e. if you disconnect and reconnect a
+	 * device immediately after, it should be assigned a different session ID).
+	 * If your OS cannot provide a unique session ID as described above,
+	 * presenting a session ID of (bus_number << 8 | device_address) should
+	 * be sufficient. Bus numbers and device addresses wrap and get reused,
+	 * but that is an unlikely case.
+	 *
+	 * After computing a session ID for a device, call
+	 * usbi_get_device_by_session_id(). This function checks if libusb already
+	 * knows about the device, and if so, it provides you with a libusb_device
+	 * structure for it.
+	 *
+	 * If usbi_get_device_by_session_id() returns NULL, it is time to allocate
+	 * a new device structure for the device. Call usbi_alloc_device() to
+	 * obtain a new libusb_device structure with reference count 1. Populate
+	 * the bus_number and device_address attributes of the new device, and
+	 * perform any other internal backend initialization you need to do. At
+	 * this point, you should be ready to provide device descriptors and so
+	 * on through the get_*_descriptor functions. Finally, call
+	 * usbi_sanitize_device() to perform some final sanity checks on the
+	 * device. Assuming all of the above succeeded, we can now continue.
+	 * If any of the above failed, remember to unreference the device that
+	 * was returned by usbi_alloc_device().
+	 *
+	 * At this stage we have a populated libusb_device structure (either one
+	 * that was found earlier, or one that we have just allocated and
+	 * populated). This can now be added to the discovered devices list
+	 * using discovered_devs_append(). Note that discovered_devs_append()
+	 * may reallocate the list, returning a new location for it, and also
+	 * note that reallocation can fail. Your backend should handle these
+	 * error conditions appropriately.
+	 *
+	 * This function should not generate any bus I/O and should not block.
+	 * If I/O is required (e.g. reading the active configuration value), it is
+	 * OK to ignore these suggestions :)
+	 *
+	 * This function is executed when the user wishes to retrieve a list
+	 * of USB devices connected to the system.
+	 *
+	 * Return 0 on success, or a LIBUSB_ERROR code on failure.
+	 */
+	int (*get_device_list)(struct libusb_context *ctx,
+		struct discovered_devs **discdevs);
+
+	/* Open a device for I/O and other USB operations. The device handle
+	 * is preallocated for you, you can retrieve the device in question
+	 * through handle->dev.
+	 *
+	 * Your backend should allocate any internal resources required for I/O
+	 * and other operations so that those operations can happen (hopefully)
+	 * without hiccup. This is also a good place to inform libusb that it
+	 * should monitor certain file descriptors related to this device -
+	 * see the usbi_add_pollfd() function.
+	 *
+	 * This function should not generate any bus I/O and should not block.
+	 *
+	 * This function is called when the user attempts to obtain a device
+	 * handle for a device.
+	 *
+	 * Return:
+	 * - 0 on success
+	 * - LIBUSB_ERROR_ACCESS if the user has insufficient permissions
+	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since
+	 *   discovery
+	 * - another LIBUSB_ERROR code on other failure
+	 *
+	 * Do not worry about freeing the handle on failed open, the upper layers
+	 * do this for you.
+	 */
+	int (*open)(struct libusb_device_handle *handle);
+
+	/* Close a device such that the handle cannot be used again. Your backend
+	 * should destroy any resources that were allocated in the open path.
+	 * This may also be a good place to call usbi_remove_pollfd() to inform
+	 * libusb of any file descriptors associated with this device that should
+	 * no longer be monitored.
+	 *
+	 * This function is called when the user closes a device handle.
+	 */
+	void (*close)(struct libusb_device_handle *handle);
+
+	/* Retrieve the device descriptor from a device.
+	 *
+	 * The descriptor should be retrieved from memory, NOT via bus I/O to the
+	 * device. This means that you may have to cache it in a private structure
+	 * during get_device_list enumeration. Alternatively, you may be able
+	 * to retrieve it from a kernel interface (some Linux setups can do this)
+	 * still without generating bus I/O.
+	 *
+	 * This function is expected to write DEVICE_DESC_LENGTH (18) bytes into
+	 * buffer, which is guaranteed to be big enough.
+	 *
+	 * This function is called when sanity-checking a device before adding
+	 * it to the list of discovered devices, and also when the user requests
+	 * to read the device descriptor.
+	 *
+	 * This function is expected to return the descriptor in bus-endian format
+	 * (LE). If it returns the multi-byte values in host-endian format,
+	 * set the host_endian output parameter to "1".
+	 *
+	 * Return 0 on success or a LIBUSB_ERROR code on failure.
+	 */
+	int (*get_device_descriptor)(struct libusb_device *device,
+		unsigned char *buffer, int *host_endian);
+
+	/* Get the ACTIVE configuration descriptor for a device.
+	 *
+	 * The descriptor should be retrieved from memory, NOT via bus I/O to the
+	 * device. This means that you may have to cache it in a private structure
+	 * during get_device_list enumeration. You may also have to keep track
+	 * of which configuration is active when the user changes it.
+	 *
+	 * This function is expected to write len bytes of data into buffer, which
+	 * is guaranteed to be big enough. If you can only do a partial write,
+	 * return an error code.
+	 *
+	 * This function is expected to return the descriptor in bus-endian format
+	 * (LE). If it returns the multi-byte values in host-endian format,
+	 * set the host_endian output parameter to "1".
+	 *
+	 * Return:
+	 * - 0 on success
+	 * - LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state
+	 * - another LIBUSB_ERROR code on other failure
+	 */
+	int (*get_active_config_descriptor)(struct libusb_device *device,
+		unsigned char *buffer, size_t len, int *host_endian);
+
+	/* Get a specific configuration descriptor for a device.
+	 *
+	 * The descriptor should be retrieved from memory, NOT via bus I/O to the
+	 * device. This means that you may have to cache it in a private structure
+	 * during get_device_list enumeration.
+	 *
+	 * The requested descriptor is expressed as a zero-based index (i.e. 0
+	 * indicates that we are requesting the first descriptor). The index does
+	 * not (necessarily) equal the bConfigurationValue of the configuration
+	 * being requested.
+	 *
+	 * This function is expected to write len bytes of data into buffer, which
+	 * is guaranteed to be big enough. If you can only do a partial write,
+	 * return an error code.
+	 *
+	 * This function is expected to return the descriptor in bus-endian format
+	 * (LE). If it returns the multi-byte values in host-endian format,
+	 * set the host_endian output parameter to "1".
+	 *
+	 * Return 0 on success or a LIBUSB_ERROR code on failure.
+	 */
+	int (*get_config_descriptor)(struct libusb_device *device,
+		uint8_t config_index, unsigned char *buffer, size_t len,
+		int *host_endian);
+
+	/* Get the bConfigurationValue for the active configuration for a device.
+	 * Optional. This should only be implemented if you can retrieve it from
+	 * cache (don't generate I/O).
+	 *
+	 * If you cannot retrieve this from cache, either do not implement this
+	 * function, or return LIBUSB_ERROR_NOT_SUPPORTED. This will cause
+	 * libusb to retrieve the information through a standard control transfer.
+	 *
+	 * This function must be non-blocking.
+	 * Return:
+	 * - 0 on success
+	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+	 *   was opened
+	 * - LIBUSB_ERROR_NOT_SUPPORTED if the value cannot be retrieved without
+	 *   blocking
+	 * - another LIBUSB_ERROR code on other failure.
+	 */
+	int (*get_configuration)(struct libusb_device_handle *handle, int *config);
+
+	/* Set the active configuration for a device.
+	 *
+	 * A configuration value of -1 should put the device in unconfigured state.
+	 *
+	 * This function can block.
+	 *
+	 * Return:
+	 * - 0 on success
+	 * - LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
+	 * - LIBUSB_ERROR_BUSY if interfaces are currently claimed (and hence
+	 *   configuration cannot be changed)
+	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+	 *   was opened
+	 * - another LIBUSB_ERROR code on other failure.
+	 */
+	int (*set_configuration)(struct libusb_device_handle *handle, int config);
+
+	/* Claim an interface. When claimed, the application can then perform
+	 * I/O to an interface's endpoints.
+	 *
+	 * This function should not generate any bus I/O and should not block.
+	 * Interface claiming is a logical operation that simply ensures that
+	 * no other drivers/applications are using the interface, and after
+	 * claiming, no other drivers/applicatiosn can use the interface because
+	 * we now "own" it.
+	 *
+	 * Return:
+	 * - 0 on success
+	 * - LIBUSB_ERROR_NOT_FOUND if the interface does not exist
+	 * - LIBUSB_ERROR_BUSY if the interface is in use by another driver/app
+	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+	 *   was opened
+	 * - another LIBUSB_ERROR code on other failure
+	 */
+	int (*claim_interface)(struct libusb_device_handle *handle, int interface_number);
+
+	/* Release a previously claimed interface.
+	 *
+	 * This function should also generate a SET_INTERFACE control request,
+	 * resetting the alternate setting of that interface to 0. It's OK for
+	 * this function to block as a result.
+	 *
+	 * You will only ever be asked to release an interface which was
+	 * successfully claimed earlier.
+	 *
+	 * Return:
+	 * - 0 on success
+	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+	 *   was opened
+	 * - another LIBUSB_ERROR code on other failure
+	 */
+	int (*release_interface)(struct libusb_device_handle *handle, int interface_number);
+
+	/* Set the alternate setting for an interface.
+	 *
+	 * You will only ever be asked to set the alternate setting for an
+	 * interface which was successfully claimed earlier.
+	 *
+	 * It's OK for this function to block.
+	 *
+	 * Return:
+	 * - 0 on success
+	 * - LIBUSB_ERROR_NOT_FOUND if the alternate setting does not exist
+	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+	 *   was opened
+	 * - another LIBUSB_ERROR code on other failure
+	 */
+	int (*set_interface_altsetting)(struct libusb_device_handle *handle,
+		int interface_number, int altsetting);
+
+	/* Clear a halt/stall condition on an endpoint.
+	 *
+	 * It's OK for this function to block.
+	 *
+	 * Return:
+	 * - 0 on success
+	 * - LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist
+	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+	 *   was opened
+	 * - another LIBUSB_ERROR code on other failure
+	 */
+	int (*clear_halt)(struct libusb_device_handle *handle,
+		unsigned char endpoint);
+
+	/* Perform a USB port reset to reinitialize a device.
+	 *
+	 * If possible, the handle should still be usable after the reset
+	 * completes, assuming that the device descriptors did not change during
+	 * reset and all previous interface state can be restored.
+	 *
+	 * If something changes, or you cannot easily locate/verify the resetted
+	 * device, return LIBUSB_ERROR_NOT_FOUND. This prompts the application
+	 * to close the old handle and re-enumerate the device.
+	 *
+	 * Return:
+	 * - 0 on success
+	 * - LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the device
+	 *   has been disconnected since it was opened
+	 * - another LIBUSB_ERROR code on other failure
+	 */
+	int (*reset_device)(struct libusb_device_handle *handle);
+
+	/* Determine if a kernel driver is active on an interface. Optional.
+	 *
+	 * The presence of a kernel driver on an interface indicates that any
+	 * calls to claim_interface would fail with the LIBUSB_ERROR_BUSY code.
+	 *
+	 * Return:
+	 * - 0 if no driver is active
+	 * - 1 if a driver is active
+	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+	 *   was opened
+	 * - another LIBUSB_ERROR code on other failure
+	 */
+	int (*kernel_driver_active)(struct libusb_device_handle *handle,
+		int interface_number);
+
+	/* Detach a kernel driver from an interface. Optional.
+	 *
+	 * After detaching a kernel driver, the interface should be available
+	 * for claim.
+	 *
+	 * Return:
+	 * - 0 on success
+	 * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active
+	 * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist
+	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+	 *   was opened
+	 * - another LIBUSB_ERROR code on other failure
+	 */
+	int (*detach_kernel_driver)(struct libusb_device_handle *handle,
+		int interface_number);
+
+	/* Attach a kernel driver to an interface. Optional.
+	 *
+	 * Reattach a kernel driver to the device.
+	 *
+	 * Return:
+	 * - 0 on success
+	 * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active
+	 * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist
+	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+	 *   was opened
+	 * - LIBUSB_ERROR_BUSY if a program or driver has claimed the interface,
+	 *   preventing reattachment
+	 * - another LIBUSB_ERROR code on other failure
+	 */
+	int (*attach_kernel_driver)(struct libusb_device_handle *handle,
+		int interface_number);
+
+	/* Destroy a device. Optional.
+	 *
+	 * This function is called when the last reference to a device is
+	 * destroyed. It should free any resources allocated in the get_device_list
+	 * path.
+	 */
+	void (*destroy_device)(struct libusb_device *dev);
+
+	/* Submit a transfer. Your implementation should take the transfer,
+	 * morph it into whatever form your platform requires, and submit it
+	 * asynchronously.
+	 *
+	 * This function must not block.
+	 *
+	 * Return:
+	 * - 0 on success
+	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+	 * - another LIBUSB_ERROR code on other failure
+	 */
+	int (*submit_transfer)(struct usbi_transfer *itransfer);
+
+	/* Cancel a previously submitted transfer.
+	 *
+	 * This function must not block. The transfer cancellation must complete
+	 * later, resulting in a call to usbi_handle_transfer_cancellation()
+	 * from the context of handle_events.
+	 */
+	int (*cancel_transfer)(struct usbi_transfer *itransfer);
+
+	/* Clear a transfer as if it has completed or cancelled, but do not
+	 * report any completion/cancellation to the library. You should free
+	 * all private data from the transfer as if you were just about to report
+	 * completion or cancellation.
+	 *
+	 * This function might seem a bit out of place. It is used when libusb
+	 * detects a disconnected device - it calls this function for all pending
+	 * transfers before reporting completion (with the disconnect code) to
+	 * the user. Maybe we can improve upon this internal interface in future.
+	 */
+	void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
+
+	/* Handle any pending events. This involves monitoring any active
+	 * transfers and processing their completion or cancellation.
+	 *
+	 * The function is passed an array of pollfd structures (size nfds)
+	 * as a result of the poll() system call. The num_ready parameter
+	 * indicates the number of file descriptors that have reported events
+	 * (i.e. the poll() return value). This should be enough information
+	 * for you to determine which actions need to be taken on the currently
+	 * active transfers.
+	 *
+	 * For any cancelled transfers, call usbi_handle_transfer_cancellation().
+	 * For completed transfers, call usbi_handle_transfer_completion().
+	 * For control/bulk/interrupt transfers, populate the "transferred"
+	 * element of the appropriate usbi_transfer structure before calling the
+	 * above functions. For isochronous transfers, populate the status and
+	 * transferred fields of the iso packet descriptors of the transfer.
+	 *
+	 * This function should also be able to detect disconnection of the
+	 * device, reporting that situation with usbi_handle_disconnect().
+	 *
+	 * When processing an event related to a transfer, you probably want to
+	 * take usbi_transfer.lock to prevent races. See the documentation for
+	 * the usbi_transfer structure.
+	 *
+	 * Return 0 on success, or a LIBUSB_ERROR code on failure.
+	 */
+	int (*handle_events)(struct libusb_context *ctx,
+		struct pollfd *fds, 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;
+
+#endif
+
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
new file mode 100644
index 0000000..8834d0f
--- /dev/null
+++ b/libusb/os/darwin_usb.c
@@ -0,0 +1,1750 @@
+/*
+ * darwin backend for libusb 1.0
+ * Copyright (C) 2008-2011 Nathan Hjelm <hjelmn@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <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 <IOKit/IOCFBundle.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOCFPlugIn.h>
+
+#include "darwin_usb.h"
+
+/* async event thread */
+static pthread_mutex_t libusb_darwin_at_mutex;
+static pthread_cond_t  libusb_darwin_at_cond;
+
+static clock_serv_t clock_realtime;
+static clock_serv_t clock_monotonic;
+
+static CFRunLoopRef libusb_darwin_acfl = NULL; /* async 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 const char *darwin_error_str (int result) {
+  switch (result) {
+  case kIOReturnSuccess:
+    return "no error";
+  case kIOReturnNotOpen:
+    return "device not opened for exclusive access";
+  case kIOReturnNoDevice:
+    return "no connection to an IOService";
+  case kIOUSBNoAsyncPortErr:
+    return "no async port has been opened for interface";
+  case kIOReturnExclusiveAccess:
+    return "another process has device opened for exclusive access";
+  case kIOUSBPipeStalled:
+    return "pipe is stalled";
+  case kIOReturnError:
+    return "could not establish a connection to the Darwin kernel";
+  case kIOUSBTransactionTimeout:
+    return "transaction timed out";
+  case kIOReturnBadArgument:
+    return "invalid argument";
+  case kIOReturnAborted:
+    return "transaction aborted";
+  case kIOReturnNotResponding:
+    return "device not responding";
+  case kIOReturnOverrun:
+    return "data overrun";
+  case kIOReturnCannotWire:
+    return "physical memory can not be wired down";
+  default:
+    return "unknown error";
+  }
+}
+
+static int darwin_to_libusb (int result) {
+  switch (result) {
+  case kIOReturnUnderrun:
+  case kIOReturnSuccess:
+    return LIBUSB_SUCCESS;
+  case kIOReturnNotOpen:
+  case kIOReturnNoDevice:
+    return LIBUSB_ERROR_NO_DEVICE;
+  case kIOReturnExclusiveAccess:
+    return LIBUSB_ERROR_ACCESS;
+  case kIOUSBPipeStalled:
+    return LIBUSB_ERROR_PIPE;
+  case kIOReturnBadArgument:
+    return LIBUSB_ERROR_INVALID_PARAM;
+  case kIOUSBTransactionTimeout:
+    return LIBUSB_ERROR_TIMEOUT;
+  case kIOReturnNotResponding:
+  case kIOReturnAborted:
+  case kIOReturnError:
+  case kIOUSBNoAsyncPortErr:
+  default:
+    return LIBUSB_ERROR_OTHER;
+  }
+}
+
+
+static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, uint8_t *pipep, uint8_t *ifcp) {
+  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+
+  /* current interface */
+  struct darwin_interface *cInterface;
+
+  int8_t i, iface;
+
+  usbi_info (HANDLE_CTX(dev_handle), "converting ep address 0x%02x to pipeRef and interface", ep);
+
+  for (iface = 0 ; iface < USB_MAXINTERFACES ; iface++) {
+    cInterface = &priv->interfaces[iface];
+
+    if (dev_handle->claimed_interfaces & (1 << iface)) {
+      for (i = 0 ; i < cInterface->num_endpoints ; i++) {
+	if (cInterface->endpoint_addrs[i] == ep) {
+	  *pipep = i + 1;
+	  *ifcp = iface;
+	  usbi_info (HANDLE_CTX(dev_handle), "pipe %d on interface %d matches", *pipep, *ifcp);
+	  return 0;
+	}
+      }
+    }
+  }
+
+  /* No pipe found with the correct endpoint address */
+  usbi_warn (HANDLE_CTX(dev_handle), "no pipeRef found with endpoint address 0x%02x.", ep);
+
+  return -1;
+}
+
+static int usb_setup_device_iterator (io_iterator_t *deviceIterator, long location) {
+  CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
+
+  if (!matchingDict)
+    return kIOReturnError;
+
+  if (location) {
+    CFMutableDictionaryRef propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                                                         &kCFTypeDictionaryKeyCallBacks,
+                                                                         &kCFTypeDictionaryValueCallBacks);
+
+    if (propertyMatchDict) {
+      CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberLongType, &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);
+
+  (*plugInInterface)->Stop(plugInInterface);
+  IODestroyPlugInInterface (plugInInterface);
+
+  /* get the location from the device */
+  if (locationp)
+    (*(device))->GetLocationID(device, locationp);
+
+  return device;
+}
+
+static kern_return_t darwin_get_device (uint32_t dev_location, usb_device_t ***darwin_device) {
+  kern_return_t kresult;
+  UInt32        location;
+  io_iterator_t deviceIterator;
+
+  kresult = usb_setup_device_iterator (&deviceIterator, dev_location);
+  if (kresult)
+    return kresult;
+
+  /* This port of libusb uses locations to keep track of devices. */
+  while ((*darwin_device = usb_get_next_device (deviceIterator, &location)) != NULL) {
+    if (location == dev_location)
+      break;
+
+    (**darwin_device)->Release(*darwin_device);
+  }
+
+  IOObjectRelease (deviceIterator);
+
+  if (!(*darwin_device))
+    return kIOReturnNoDevice;
+
+  return kIOReturnSuccess;
+}
+
+
+
+static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
+  struct libusb_context *ctx = (struct libusb_context *)ptr;
+  struct libusb_device_handle *handle;
+  struct darwin_device_priv *dpriv;
+  struct darwin_device_handle_priv *priv;
+
+  io_service_t device;
+  long location;
+  bool locationValid;
+  CFTypeRef locationCF;
+  UInt32 message;
+
+  usbi_info (ctx, "a device has been detached");
+
+  while ((device = IOIteratorNext (rem_devices)) != 0) {
+    /* get the location from the i/o registry */
+    locationCF = IORegistryEntryCreateCFProperty (device, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault, 0);
+
+    IOObjectRelease (device);
+
+    if (!locationCF)
+      continue;
+
+    locationValid = CFGetTypeID(locationCF) == CFNumberGetTypeID() &&
+	    CFNumberGetValue(locationCF, kCFNumberLongType, &location);
+
+    CFRelease (locationCF);
+
+    if (!locationValid)
+      continue;
+
+    usbi_mutex_lock(&ctx->open_devs_lock);
+    list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
+      dpriv = (struct darwin_device_priv *)handle->dev->os_priv;
+
+      /* the device may have been opened several times. write to each handle's event descriptor */
+      if (dpriv->location == location  && handle->os_priv) {
+	priv  = (struct darwin_device_handle_priv *)handle->os_priv;
+
+	message = MESSAGE_DEVICE_GONE;
+	write (priv->fds[1], &message, sizeof (message));
+      }
+    }
+
+    usbi_mutex_unlock(&ctx->open_devs_lock);
+  }
+}
+
+static void darwin_clear_iterator (io_iterator_t iter) {
+  io_service_t device;
+
+  while ((device = IOIteratorNext (iter)) != 0)
+    IOObjectRelease (device);
+}
+
+static void *event_thread_main (void *arg0) {
+  IOReturn kresult;
+  struct libusb_context *ctx = (struct libusb_context *)arg0;
+  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-detach");
+#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 removal) source */
+  CFRunLoopSourceRef     libusb_notification_cfsource;
+  io_notification_port_t libusb_notification_port;
+  io_iterator_t          libusb_rem_device_iterator;
+
+  usbi_info (ctx, "creating hotplug event source");
+
+  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);
+  }
+
+  /* arm notifiers */
+  darwin_clear_iterator (libusb_rem_device_iterator);
+
+  usbi_info (ctx, "thread ready to receive events");
+
+  /* signal the main thread that the async 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, "thread exiting");
+
+  /* delete notification port */
+  IONotificationPortDestroy (libusb_notification_port);
+  IOObjectRelease (libusb_rem_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;
+
+  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_mutex_init (&libusb_darwin_at_mutex, NULL);
+    pthread_cond_init (&libusb_darwin_at_cond, NULL);
+
+    pthread_create (&libusb_darwin_at, NULL, 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 async 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_INVALID_PARAM;
+
+  config_index = get_configuration_index (dev, priv->active_config);
+  if (config_index < 0)
+    return config_index;
+
+  return darwin_get_config_descriptor (dev, config_index, buffer, len, host_endian);
+}
+
+static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) {
+  struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
+  IOUSBConfigurationDescriptorPtr desc;
+  IOReturn kresult;
+  usb_device_t **device = NULL;
+
+  if (!priv)
+    return LIBUSB_ERROR_OTHER;
+
+  if (!priv->device) {
+    kresult = darwin_get_device (priv->location, &device);
+    if (kresult || !device) {
+      usbi_err (DEVICE_CTX (dev), "could not find device: %s", darwin_error_str (kresult));
+
+      return darwin_to_libusb (kresult);
+    }
+
+    /* don't have to open the device to get a config descriptor */
+  } else
+    device = priv->device;
+
+  kresult = (*device)->GetConfigurationDescriptorPtr (device, config_index, &desc);
+  if (kresult == kIOReturnSuccess) {
+    /* copy descriptor */
+    if (libusb_le16_to_cpu(desc->wTotalLength) < len)
+      len = libusb_le16_to_cpu(desc->wTotalLength);
+
+    memmove (buffer, desc, len);
+
+    /* GetConfigurationDescriptorPtr returns the descriptor in USB bus order */
+    *host_endian = 0;
+  }
+
+  if (!priv->device)
+    (*device)->Release (device);
+
+  return darwin_to_libusb (kresult);
+}
+
+/* check whether the os has configured the device */
+static int darwin_check_configuration (struct libusb_context *ctx, struct libusb_device *dev, usb_device_t **darwin_device) {
+  struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
+
+  IOUSBConfigurationDescriptorPtr configDesc;
+  IOUSBFindInterfaceRequest request;
+  kern_return_t             kresult;
+  io_iterator_t             interface_iterator;
+  io_service_t              firstInterface;
+
+  if (priv->dev_descriptor.bNumConfigurations < 1) {
+    usbi_err (ctx, "device has no configurations");
+    return LIBUSB_ERROR_OTHER; /* no configurations at this speed so we can't use it */
+  }
+
+  /* find the first configuration */
+  kresult = (*darwin_device)->GetConfigurationDescriptorPtr (darwin_device, 0, &configDesc);
+  priv->first_config = (kIOReturnSuccess == kresult) ? configDesc->bConfigurationValue : 1;
+
+  /* check if the device is already configured. there is probably a better way than iterating over the
+     to accomplish this (the trick is we need to avoid a call to GetConfigurations since buggy devices
+     might lock up on the device request) */
+
+  /* Setup the Interface Request */
+  request.bInterfaceClass    = kIOUSBFindInterfaceDontCare;
+  request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+  request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+  request.bAlternateSetting  = kIOUSBFindInterfaceDontCare;
+
+  kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator);
+  if (kresult)
+    return darwin_to_libusb (kresult);
+
+  /* iterate once */
+  firstInterface = IOIteratorNext(interface_iterator);
+
+  /* done with the interface iterator */
+  IOObjectRelease(interface_iterator);
+
+  if (firstInterface) {
+    IOObjectRelease (firstInterface);
+
+    /* device is configured */
+    if (priv->dev_descriptor.bNumConfigurations == 1)
+      /* to avoid problems with some devices get the configurations value from the configuration descriptor */
+      priv->active_config = priv->first_config;
+    else
+      /* devices with more than one configuration should work with GetConfiguration */
+      (*darwin_device)->GetConfiguration (darwin_device, &priv->active_config);
+  } else
+    /* not configured */
+    priv->active_config = 0;
+  
+  usbi_info (ctx, "active config: %u, first config: %u", priv->active_config, priv->first_config);
+
+  return 0;
+}
+
+static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct libusb_device *dev, usb_device_t **device) {
+  struct darwin_device_priv *priv;
+  int retries = 5, delay = 30000;
+  int unsuspended = 0, try_unsuspend = 1, try_reconfigure = 1;
+  int is_open = 0;
+  int ret = 0, ret2;
+  IOUSBDevRequest req;
+  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 {
+    /* Set up request for device descriptor */
+    memset (&(priv->dev_descriptor), 0, sizeof(IOUSBDeviceDescriptor));
+    req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+    req.bRequest      = kUSBRqGetDescriptor;
+    req.wValue        = kUSBDeviceDesc << 8;
+    req.wIndex        = 0;
+    req.wLength       = sizeof(priv->dev_descriptor);
+    req.pData         = &(priv->dev_descriptor);
+
+    /* 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 = (*(device))->DeviceRequest (device, &req);
+
+    if (kIOReturnOverrun == ret && kUSBDeviceDesc == priv->dev_descriptor.bDescriptorType)
+      /* received an overrun error but we still received a device descriptor */
+      ret = kIOReturnSuccess;
+
+    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 discovered_devs **_discdevs) {
+  struct darwin_device_priv *priv;
+  struct libusb_device *dev;
+  struct discovered_devs *discdevs;
+  UInt16                address;
+  UInt8                 devSpeed;
+  int ret = 0, need_unref = 0;
+
+  do {
+    dev = usbi_get_device_by_session_id(ctx, locationID);
+    if (!dev) {
+      usbi_info (ctx, "allocating new device for location 0x%08x", locationID);
+      dev = usbi_alloc_device(ctx, locationID);
+      need_unref = 1;
+    } else
+      usbi_info (ctx, "using existing device for location 0x%08x", locationID);
+
+    if (!dev) {
+      ret = LIBUSB_ERROR_NO_MEM;
+      break;
+    }
+
+    priv = (struct darwin_device_priv *)dev->os_priv;
+
+    (*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;
+    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;
+
+    /* append the device to the list of discovered devices */
+    discdevs = discovered_devs_append(*_discdevs, dev);
+    if (!discdevs) {
+      ret = LIBUSB_ERROR_NO_MEM;
+      break;
+    }
+
+    *_discdevs = discdevs;
+
+    usbi_info (ctx, "found device with address %d at %s", dev->device_address, priv->sys_path);
+  } while (0);
+
+  if (need_unref)
+    libusb_unref_device(dev);
+
+  return ret;
+}
+
+static int darwin_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) {
+  io_iterator_t        deviceIterator;
+  usb_device_t         **device;
+  kern_return_t        kresult;
+  UInt32               location;
+
+  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, _discdevs);
+
+    (*(device))->Release(device);
+  }
+
+  IOObjectRelease(deviceIterator);
+
+  return 0;
+}
+
+static int darwin_open (struct libusb_device_handle *dev_handle) {
+  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+  struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+  usb_device_t  **darwin_device;
+  IOReturn kresult;
+
+  if (0 == dpriv->open_count) {
+    kresult = darwin_get_device (dpriv->location, &darwin_device);
+    if (kresult) {
+      usbi_err (HANDLE_CTX (dev_handle), "could not find device: %s", darwin_error_str (kresult));
+      return darwin_to_libusb (kresult);
+    }
+
+    dpriv->device = darwin_device;
+
+    /* try to open the device */
+    kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device);
+
+    if (kresult != kIOReturnSuccess) {
+      usbi_err (HANDLE_CTX (dev_handle), "USBDeviceOpen: %s", darwin_error_str(kresult));
+
+      switch (kresult) {
+      case kIOReturnExclusiveAccess:
+	/* it is possible to perform some actions on a device that is not open so do not return an error */
+	priv->is_open = 0;
+
+	break;
+      default:
+	(*(dpriv->device))->Release (dpriv->device);
+	dpriv->device = NULL;
+	return darwin_to_libusb (kresult);
+      }
+    } else {
+      /* 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));
+
+	(*(dpriv->device))->USBDeviceClose (dpriv->device);
+	(*(dpriv->device))->Release (dpriv->device);
+
+	dpriv->device = NULL;
+	return darwin_to_libusb (kresult);
+      }
+
+      priv->is_open = 1;
+
+      CFRetain (libusb_darwin_acfl);
+
+      /* add the cfSource to the aync run loop */
+      CFRunLoopAddSource(libusb_darwin_acfl, priv->cfSource, kCFRunLoopCommonModes);
+    }
+  }
+
+  /* device opened successfully */
+  dpriv->open_count++;
+
+  /* create a file descriptor for notifications */
+  pipe (priv->fds);
+
+  /* set the pipe to be non-blocking */
+  fcntl (priv->fds[1], F_SETFD, O_NONBLOCK);
+
+  usbi_add_pollfd(HANDLE_CTX(dev_handle), priv->fds[0], POLLIN);
+
+  usbi_info (HANDLE_CTX (dev_handle), "device open for access");
+
+  return 0;
+}
+
+static void darwin_close (struct libusb_device_handle *dev_handle) {
+  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+  struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+  IOReturn kresult;
+  int i;
+
+  if (dpriv->open_count == 0) {
+    /* something is probably very wrong if this is the case */
+    usbi_err (HANDLE_CTX (dev_handle), "Close called on a device that was not open!\n");
+    return;
+  }
+
+  dpriv->open_count--;
+
+  /* make sure all interfaces are released */
+  for (i = 0 ; i < USB_MAXINTERFACES ; i++)
+    if (dev_handle->claimed_interfaces & (1 << i))
+      libusb_release_interface (dev_handle, i);
+
+  if (0 == dpriv->open_count) {
+    if (priv->is_open) {
+      /* delete the device's async event source */
+      if (priv->cfSource) {
+	CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode);
+	CFRelease (priv->cfSource);
+      }
+
+      /* close the device */
+      kresult = (*(dpriv->device))->USBDeviceClose(dpriv->device);
+      if (kresult) {
+	/* Log the fact that we had a problem closing the file, however failing a
+	 * close isn't really an error, so return success anyway */
+	usbi_err (HANDLE_CTX (dev_handle), "USBDeviceClose: %s", darwin_error_str(kresult));
+      }
+    }
+
+    kresult = (*(dpriv->device))->Release(dpriv->device);
+    if (kresult) {
+      /* Log the fact that we had a problem closing the file, however failing a
+       * close isn't really an error, so return success anyway */
+      usbi_err (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult));
+    }
+
+    dpriv->device = NULL;
+  }
+
+  /* file descriptors are maintained per-instance */
+  usbi_remove_pollfd (HANDLE_CTX (dev_handle), priv->fds[0]);
+  close (priv->fds[1]);
+  close (priv->fds[0]);
+
+  priv->fds[0] = priv->fds[1] = -1;
+}
+
+static int darwin_get_configuration(struct libusb_device_handle *dev_handle, int *config) {
+  struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+
+  *config = (int) dpriv->active_config;
+
+  return 0;
+}
+
+static int darwin_set_configuration(struct libusb_device_handle *dev_handle, int config) {
+  struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+  IOReturn kresult;
+  int i;
+
+  /* Setting configuration will invalidate the interface, so we need
+     to reclaim it. First, dispose of existing interfaces, if any. */
+  for (i = 0 ; i < USB_MAXINTERFACES ; i++)
+    if (dev_handle->claimed_interfaces & (1 << i))
+      darwin_release_interface (dev_handle, i);
+
+  kresult = (*(dpriv->device))->SetConfiguration (dpriv->device, config);
+  if (kresult != kIOReturnSuccess)
+    return darwin_to_libusb (kresult);
+
+  /* Reclaim any interfaces. */
+  for (i = 0 ; i < USB_MAXINTERFACES ; i++)
+    if (dev_handle->claimed_interfaces & (1 << i))
+      darwin_claim_interface (dev_handle, i);
+
+  dpriv->active_config = config;
+
+  return 0;
+}
+
+static int darwin_get_interface (usb_device_t **darwin_device, uint8_t ifc, io_service_t *usbInterfacep) {
+  IOUSBFindInterfaceRequest request;
+  uint8_t                   current_interface;
+  kern_return_t             kresult;
+  io_iterator_t             interface_iterator;
+
+  *usbInterfacep = IO_OBJECT_NULL;
+
+  /* Setup the Interface Request */
+  request.bInterfaceClass    = kIOUSBFindInterfaceDontCare;
+  request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+  request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+  request.bAlternateSetting  = kIOUSBFindInterfaceDontCare;
+
+  kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator);
+  if (kresult)
+    return kresult;
+
+  for ( current_interface = 0 ; current_interface <= ifc ; current_interface++ ) {
+    *usbInterfacep = IOIteratorNext(interface_iterator);
+    if (current_interface != ifc)
+      (void) IOObjectRelease (*usbInterfacep);
+  }
+
+  /* done with the interface iterator */
+  IOObjectRelease(interface_iterator);
+
+  return 0;
+}
+
+static int get_endpoints (struct libusb_device_handle *dev_handle, int iface) {
+  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+
+  /* current interface */
+  struct darwin_interface *cInterface = &priv->interfaces[iface];
+
+  kern_return_t kresult;
+
+  u_int8_t numep, direction, number;
+  u_int8_t dont_care1, dont_care3;
+  u_int16_t dont_care2;
+  int i;
+
+  usbi_info (HANDLE_CTX (dev_handle), "building table of endpoints.");
+
+  /* retrieve the total number of endpoints on this interface */
+  kresult = (*(cInterface->interface))->GetNumEndpoints(cInterface->interface, &numep);
+  if (kresult) {
+    usbi_err (HANDLE_CTX (dev_handle), "can't get number of endpoints for interface: %s", darwin_error_str(kresult));
+    return darwin_to_libusb (kresult);
+  }
+
+  /* iterate through pipe references */
+  for (i = 1 ; i <= numep ; i++) {
+    kresult = (*(cInterface->interface))->GetPipeProperties(cInterface->interface, i, &direction, &number, &dont_care1,
+							    &dont_care2, &dont_care3);
+
+    if (kresult != kIOReturnSuccess) {
+      usbi_err (HANDLE_CTX (dev_handle), "error getting pipe information for pipe %d: %s", i, darwin_error_str(kresult));
+
+      return darwin_to_libusb (kresult);
+    }
+
+    usbi_info (HANDLE_CTX (dev_handle), "interface: %i pipe %i: dir: %i number: %i", iface, i, direction, number);
+
+    cInterface->endpoint_addrs[i - 1] = ((direction << 7 & LIBUSB_ENDPOINT_DIR_MASK) | (number & LIBUSB_ENDPOINT_ADDRESS_MASK));
+  }
+
+  cInterface->num_endpoints = numep;
+
+  return 0;
+}
+
+static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface) {
+  struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv;
+  io_service_t          usbInterface = IO_OBJECT_NULL;
+  IOReturn kresult;
+  IOCFPlugInInterface **plugInInterface = NULL;
+  SInt32                score;
+
+  /* current interface */
+  struct darwin_interface *cInterface = &priv->interfaces[iface];
+
+  kresult = darwin_get_interface (dpriv->device, iface, &usbInterface);
+  if (kresult != kIOReturnSuccess)
+    return darwin_to_libusb (kresult);
+
+  /* make sure we have an interface */
+  if (!usbInterface && dpriv->first_config != 0) {
+    usbi_info (HANDLE_CTX (dev_handle), "no interface found; setting configuration: %d", dpriv->first_config);
+
+    /* set the configuration */
+    kresult = darwin_set_configuration (dev_handle, dpriv->first_config);
+    if (kresult != LIBUSB_SUCCESS) {
+      usbi_err (HANDLE_CTX (dev_handle), "could not set configuration");
+      return kresult;
+    }
+
+    kresult = darwin_get_interface (dpriv->device, iface, &usbInterface);
+    if (kresult) {
+      usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult));
+      return darwin_to_libusb (kresult);
+    }
+  }
+
+  if (!usbInterface) {
+    usbi_err (HANDLE_CTX (dev_handle), "interface not found");
+    return LIBUSB_ERROR_NOT_FOUND;
+  }
+
+  /* get an interface to the device's interface */
+  kresult = IOCreatePlugInInterfaceForService (usbInterface, kIOUSBInterfaceUserClientTypeID,
+					       kIOCFPlugInInterfaceID, &plugInInterface, &score);
+
+  /* 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 */
+  IODestroyPlugInInterface (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;
+  IOReturn kresult;
+
+  kresult = (*(dpriv->device))->ResetDevice (dpriv->device);
+  if (kresult)
+    usbi_err (HANDLE_CTX (dev_handle), "ResetDevice: %s", darwin_error_str (kresult));
+
+  return darwin_to_libusb (kresult);
+}
+
+static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, int interface) {
+  struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv;
+  io_service_t usbInterface;
+  CFTypeRef driver;
+  IOReturn kresult;
+
+  kresult = darwin_get_interface (dpriv->device, interface, &usbInterface);
+  if (kresult) {
+    usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult));
+
+    return darwin_to_libusb (kresult);
+  }
+
+  driver = IORegistryEntryCreateCFProperty (usbInterface, kIOBundleIdentifierKey, kCFAllocatorDefault, 0);
+  IOObjectRelease (usbInterface);
+
+  if (driver) {
+    CFRelease (driver);
+
+    return 1;
+  }
+
+  /* no driver */
+  return 0;
+}
+
+/* attaching/detaching kernel drivers is not currently supported (maybe in the future?) */
+static int darwin_attach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
+  (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) {
+  (void)dev;
+}
+
+static int submit_bulk_transfer(struct usbi_transfer *itransfer) {
+  struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+  struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv;
+
+  IOReturn               ret;
+  uint8_t                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 (IS_XFEROUT(transfer) && transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)
+    return LIBUSB_ERROR_NOT_SUPPORTED;
+
+  if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) {
+    usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
+
+    return LIBUSB_ERROR_NOT_FOUND;
+  }
+
+  cInterface = &priv->interfaces[iface];
+
+  (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
+						 &transferType, &maxPacketSize, &interval);
+
+  /* submit the request */
+  /* timeouts are unavailable on interrupt endpoints */
+  if (transferType == kUSBInterrupt) {
+    if (IS_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                 pipeRef, iface;
+  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];
+
+  /* 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);
+
+  cInterface->frames[transfer->endpoint] = frame + transfer->num_iso_packets / 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;
+  UInt32 message, size;
+
+  usbi_info (ITRANSFER_CTX (itransfer), "an async io operation has completed");
+
+  size = (UInt32) (uintptr_t) arg0;
+
+  /* send a completion message to the device's file descriptor */
+  message = MESSAGE_ASYNC_IO_COMPLETE;
+  write (priv->fds[1], &message, sizeof (message));
+  write (priv->fds[1], &itransfer, sizeof (itransfer));
+  write (priv->fds[1], &result, sizeof (IOReturn));
+  write (priv->fds[1], &size, sizeof (size));
+}
+
+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 usbi_transfer *itransfer;
+  UInt32 io_size;
+  IOReturn kresult;
+  POLL_NFDS_TYPE i = 0;
+  ssize_t ret;
+  UInt32 message;
+
+  usbi_mutex_lock(&ctx->open_devs_lock);
+  for (i = 0; i < nfds && num_ready > 0; i++) {
+    struct pollfd *pollfd = &fds[i];
+    struct libusb_device_handle *handle;
+    struct darwin_device_handle_priv *hpriv = NULL;
+
+    usbi_info (ctx, "checking fd %i with revents = %x", fds[i], pollfd->revents);
+
+    if (!pollfd->revents)
+      continue;
+
+    num_ready--;
+    list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
+      hpriv =  (struct darwin_device_handle_priv *)handle->os_priv;
+      if (hpriv->fds[0] == pollfd->fd)
+	break;
+    }
+
+    if (!(pollfd->revents & POLLERR)) {
+      ret = read (hpriv->fds[0], &message, sizeof (message));
+      if (ret < (ssize_t)sizeof (message))
+	continue;
+    } else
+      /* could not poll the device-- response is to delete the device (this seems a little heavy-handed) */
+      message = MESSAGE_DEVICE_GONE;
+
+    switch (message) {
+    case MESSAGE_DEVICE_GONE:
+      /* remove the device's async port from the runloop */
+      if (hpriv->cfSource) {
+	if (libusb_darwin_acfl)
+	  CFRunLoopRemoveSource (libusb_darwin_acfl, hpriv->cfSource, kCFRunLoopDefaultMode);
+	CFRelease (hpriv->cfSource);
+	hpriv->cfSource = NULL;
+      }
+
+      usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fds[0]);
+      usbi_handle_disconnect(handle);
+
+      /* done with this device */
+      continue;
+    case MESSAGE_ASYNC_IO_COMPLETE:
+      read (hpriv->fds[0], &itransfer, sizeof (itransfer));
+      read (hpriv->fds[0], &kresult, sizeof (IOReturn));
+      read (hpriv->fds[0], &io_size, sizeof (UInt32));
+
+      darwin_handle_callback (itransfer, kresult, io_size);
+      break;
+    default:
+      usbi_err (ctx, "unknown message received from device pipe");
+    }
+  }
+
+  usbi_mutex_unlock(&ctx->open_devs_lock);
+
+  return 0;
+}
+
+static int darwin_clock_gettime(int clk_id, struct timespec *tp) {
+  mach_timespec_t sys_time;
+  clock_serv_t clock_ref;
+
+  switch (clk_id) {
+  case USBI_CLOCK_REALTIME:
+    /* CLOCK_REALTIME represents time since the epoch */
+    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 = darwin_get_device_list,
+	.get_device_descriptor = darwin_get_device_descriptor,
+	.get_active_config_descriptor = darwin_get_active_config_descriptor,
+	.get_config_descriptor = darwin_get_config_descriptor,
+
+	.open = darwin_open,
+	.close = darwin_close,
+	.get_configuration = darwin_get_configuration,
+	.set_configuration = darwin_set_configuration,
+	.claim_interface = darwin_claim_interface,
+	.release_interface = darwin_release_interface,
+
+	.set_interface_altsetting = darwin_set_interface_altsetting,
+	.clear_halt = darwin_clear_halt,
+	.reset_device = darwin_reset_device,
+
+	.kernel_driver_active = darwin_kernel_driver_active,
+	.detach_kernel_driver = darwin_detach_kernel_driver,
+	.attach_kernel_driver = darwin_attach_kernel_driver,
+
+	.destroy_device = darwin_destroy_device,
+
+	.submit_transfer = darwin_submit_transfer,
+	.cancel_transfer = darwin_cancel_transfer,
+	.clear_transfer_priv = darwin_clear_transfer_priv,
+
+	.handle_events = op_handle_events,
+
+	.clock_gettime = darwin_clock_gettime,
+
+	.device_priv_size = sizeof(struct darwin_device_priv),
+	.device_handle_priv_size = sizeof(struct darwin_device_handle_priv),
+	.transfer_priv_size = sizeof(struct darwin_transfer_priv),
+	.add_iso_packet_size = 0,
+};
+
diff --git a/libusb/os/darwin_usb.h b/libusb/os/darwin_usb.h
new file mode 100644
index 0000000..59d0a69
--- /dev/null
+++ b/libusb/os/darwin_usb.h
@@ -0,0 +1,169 @@
+/*
+ * darwin backend for libusb 1.0
+ * Copyright (C) 2008-2009 Nathan Hjelm <hjelmn@users.sourceforge.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if !defined(LIBUSB_DARWIN_H)
+#define LIBUSB_DARWIN_H
+
+#include "libusbi.h"
+
+#include <IOKit/IOTypes.h>
+#include <IOKit/IOCFBundle.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOCFPlugIn.h>
+
+/* IOUSBInterfaceInferface */
+#if defined (kIOUSBInterfaceInterfaceID300)
+
+#define usb_interface_t IOUSBInterfaceInterface300
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300
+#define InterfaceVersion 300
+
+#elif defined (kIOUSBInterfaceInterfaceID245)
+
+#define usb_interface_t IOUSBInterfaceInterface245
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245
+#define InterfaceVersion 245
+
+#elif defined (kIOUSBInterfaceInterfaceID220)
+
+#define usb_interface_t IOUSBInterfaceInterface220
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
+#define InterfaceVersion 220
+
+#elif defined (kIOUSBInterfaceInterfaceID197)
+
+#define usb_interface_t IOUSBInterfaceInterface197
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197
+#define InterfaceVersion 197
+
+#elif defined (kIOUSBInterfaceInterfaceID190)
+
+#define usb_interface_t IOUSBInterfaceInterface190
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190
+#define InterfaceVersion 190
+
+#elif defined (kIOUSBInterfaceInterfaceID182)
+
+#define usb_interface_t IOUSBInterfaceInterface182
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182
+#define InterfaceVersion 182
+
+#else
+
+#error "IOUSBFamily is too old. Please upgrade your OS"
+
+#endif
+
+/* IOUSBDeviceInterface */
+#if defined (kIOUSBDeviceInterfaceID320)
+
+#define usb_device_t    IOUSBDeviceInterface320
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID320
+#define DeviceVersion 320
+
+#elif defined (kIOUSBDeviceInterfaceID300)
+
+#define usb_device_t    IOUSBDeviceInterface300
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID300
+#define DeviceVersion 300
+
+#elif defined (kIOUSBDeviceInterfaceID245)
+
+#define usb_device_t    IOUSBDeviceInterface245
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID245
+#define DeviceVersion 245
+
+#elif defined (kIOUSBDeviceInterfaceID197)
+
+#define usb_device_t    IOUSBDeviceInterface197
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
+#define DeviceVersion 197
+
+#elif defined (kIOUSBDeviceInterfaceID187)
+
+#define usb_device_t    IOUSBDeviceInterface187
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID187
+#define DeviceVersion 187
+
+#elif defined (kIOUSBDeviceInterfaceID182)
+
+#define usb_device_t    IOUSBDeviceInterface182
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID182
+#define DeviceVersion 182
+
+#else
+
+#error "IOUSBFamily is too old. Please upgrade your OS"
+
+#endif
+
+#if !defined(IO_OBJECT_NULL)
+#define IO_OBJECT_NULL ((io_object_t) 0)
+#endif
+
+typedef IOCFPlugInInterface *io_cf_plugin_ref_t;
+typedef IONotificationPortRef io_notification_port_t;
+
+/* private structures */
+struct darwin_device_priv {
+  IOUSBDeviceDescriptor dev_descriptor;
+  UInt32                location;
+  char                  sys_path[21];
+  usb_device_t        **device;
+  int                   open_count;
+  UInt8                 first_config, active_config;
+};
+
+struct darwin_device_handle_priv {
+  int                  is_open;
+  CFRunLoopSourceRef   cfSource;
+  int                  fds[2];
+
+  struct darwin_interface {
+    usb_interface_t    **interface;
+    uint8_t              num_endpoints;
+    CFRunLoopSourceRef   cfSource;
+    uint64_t             frames[256];
+    uint8_t            endpoint_addrs[USB_MAXENDPOINTS];
+  } interfaces[USB_MAXINTERFACES];
+};
+
+struct darwin_transfer_priv {
+  /* Isoc */
+  IOUSBIsocFrame *isoc_framelist;
+  size_t num_iso_packets;
+
+  /* Control */
+#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
+  IOUSBDevRequestTO req;
+#else
+  IOUSBDevRequest req;
+#endif
+
+  /* Bulk */
+};
+
+enum {
+  MESSAGE_DEVICE_GONE,
+  MESSAGE_ASYNC_IO_COMPLETE
+};
+
+
+
+#endif
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
new file mode 100644
index 0000000..02d182d
--- /dev/null
+++ b/libusb/os/linux_usbfs.c
@@ -0,0 +1,2438 @@
+/*
+ * Linux usbfs backend for libusb
+ * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include "libusb.h"
+#include "libusbi.h"
+#include "linux_usbfs.h"
+
+/* sysfs vs usbfs:
+ * opening a usbfs node causes the device to be resumed, so we attempt to
+ * avoid this during enumeration.
+ *
+ * sysfs allows us to read the kernel's in-memory copies of device descriptors
+ * and so forth, avoiding the need to open the device:
+ *  - The binary "descriptors" file was added in 2.6.23.
+ *  - The "busnum" file was added in 2.6.22
+ *  - The "devnum" file has been present since pre-2.6.18
+ *  - the "bConfigurationValue" file has been present since pre-2.6.18
+ *
+ * If we have bConfigurationValue, busnum, and devnum, then we can determine
+ * the active configuration without having to open the usbfs node in RDWR mode.
+ * We assume this is the case if we see the busnum file (indicates 2.6.22+).
+ * The busnum file is important as that is the only way we can relate sysfs
+ * devices to usbfs nodes.
+ *
+ * If we also have descriptors, we can obtain the device descriptor and active 
+ * configuration without touching usbfs at all.
+ *
+ * The descriptors file originally only contained the active configuration
+ * descriptor alongside the device descriptor, but all configurations are
+ * included as of Linux 2.6.26.
+ */
+
+/* endianness for multi-byte fields:
+ *
+ * Descriptors exposed by usbfs have the multi-byte fields in the device
+ * descriptor as host endian. Multi-byte fields in the other descriptors are
+ * bus-endian. The kernel documentation says otherwise, but it is wrong.
+ */
+
+static const char *usbfs_path = NULL;
+
+/* 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;
+
+struct linux_device_priv {
+	char *sysfs_dir;
+	unsigned char *dev_descriptor;
+	unsigned char *config_descriptor;
+};
+
+struct linux_device_handle_priv {
+	int fd;
+};
+
+enum reap_action {
+	NORMAL = 0,
+	/* submission failed after the first URB, so await cancellation/completion
+	 * of all the others */
+	SUBMIT_FAILED,
+
+	/* cancelled by user or timeout */
+	CANCELLED,
+
+	/* completed multi-URB transfer in non-final URB */
+	COMPLETED_EARLY,
+
+	/* one or more urbs encountered a low-level error */
+	ERROR,
+};
+
+struct linux_transfer_priv {
+	union {
+		struct usbfs_urb *urbs;
+		struct usbfs_urb **iso_urbs;
+	};
+
+	enum reap_action reap_action;
+	int num_urbs;
+	unsigned int num_retired;
+	enum libusb_transfer_status reap_status;
+
+	/* next iso packet in user-supplied transfer to be populated */
+	int iso_packet_offset;
+};
+
+static void _get_usbfs_path(struct libusb_device *dev, char *path)
+{
+	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;
+	}
+
+	return 0;
+}
+
+static int usbfs_get_device_descriptor(struct libusb_device *dev,
+	unsigned char *buffer)
+{
+	struct linux_device_priv *priv = _device_priv(dev);
+
+	/* return cached copy */
+	memcpy(buffer, priv->dev_descriptor, DEVICE_DESC_LENGTH);
+	return 0;
+}
+
+static int _open_sysfs_attr(struct libusb_device *dev, const char *attr)
+{
+	struct linux_device_priv *priv = _device_priv(dev);
+	char filename[PATH_MAX];
+	int fd;
+
+	snprintf(filename, PATH_MAX, "%s/%s/%s",
+		SYSFS_DEVICE_PATH, priv->sysfs_dir, attr);
+	fd = open(filename, O_RDONLY);
+	if (fd < 0) {
+		usbi_err(DEVICE_CTX(dev),
+			"open %s failed ret=%d errno=%d", filename, fd, errno);
+		return LIBUSB_ERROR_IO;
+	}
+
+	return fd;
+}
+
+/* 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) {
+		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;
+}
+
+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;
+}
+
+static int enumerate_device(struct libusb_context *ctx,
+	struct discovered_devs **_discdevs, uint8_t busnum, uint8_t devaddr,
+	const char *sysfs_dir)
+{
+	struct discovered_devs *discdevs;
+	unsigned long session_id;
+	int need_unref = 0;
+	struct libusb_device *dev;
+	int r = 0;
+
+	/* FIXME: session ID is not guaranteed unique as addresses can wrap and
+	 * will be reused. instead we should add a simple sysfs attribute with
+	 * a session ID. */
+	session_id = busnum << 8 | devaddr;
+	usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr,
+		session_id);
+
+	dev = usbi_get_device_by_session_id(ctx, session_id);
+	if (dev) {
+		usbi_dbg("using existing device for %d/%d (session %ld)",
+			busnum, devaddr, session_id);
+	} else {
+		usbi_dbg("allocating new device for %d/%d (session %ld)",
+			busnum, devaddr, session_id);
+		dev = usbi_alloc_device(ctx, session_id);
+		if (!dev)
+			return LIBUSB_ERROR_NO_MEM;
+		need_unref = 1;
+		r = initialize_device(dev, busnum, devaddr, sysfs_dir);
+		if (r < 0)
+			goto out;
+		r = usbi_sanitize_device(dev);
+		if (r < 0)
+			goto out;
+	}
+
+	discdevs = discovered_devs_append(*_discdevs, dev);
+	if (!discdevs)
+		r = LIBUSB_ERROR_NO_MEM;
+	else
+		*_discdevs = discdevs;
+
+out:
+	if (need_unref)
+		libusb_unref_device(dev);
+	return r;
+}
+
+/* open a bus directory and adds all discovered devices to discdevs. on
+ * failure (non-zero return) the pre-existing discdevs should be destroyed
+ * (and devices freed). on success, the new discdevs pointer should be used
+ * as it may have been moved. */
+static int usbfs_scan_busdir(struct libusb_context *ctx,
+	struct discovered_devs **_discdevs, uint8_t busnum)
+{
+	DIR *dir;
+	char dirpath[PATH_MAX];
+	struct dirent *entry;
+	struct discovered_devs *discdevs = *_discdevs;
+	int r = 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 (enumerate_device(ctx, &discdevs, busnum, (uint8_t) devaddr, NULL)) {
+			usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
+			continue;
+		}
+
+		r = 0;
+	}
+
+	if (!r)
+		*_discdevs = discdevs;
+	closedir(dir);
+	return r;
+}
+
+static int usbfs_get_device_list(struct libusb_context *ctx,
+	struct discovered_devs **_discdevs)
+{
+	struct dirent *entry;
+	DIR *buses = opendir(usbfs_path);
+	struct discovered_devs *discdevs = *_discdevs;
+	int r = 0;
+
+	if (!buses) {
+		usbi_err(ctx, "opendir buses failed errno=%d", errno);
+		return LIBUSB_ERROR_IO;
+	}
+
+	while ((entry = readdir(buses))) {
+		struct discovered_devs *discdevs_new = discdevs;
+		int busnum;
+
+		if (entry->d_name[0] == '.')
+			continue;
+
+		if (usbdev_names) {
+			int devaddr;
+			if (!_is_usbdev_entry(entry, &busnum, &devaddr))
+				continue;
+
+			r = enumerate_device(ctx, &discdevs_new, 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, &discdevs_new, busnum);
+			if (r < 0)
+				goto out;
+		}
+		discdevs = discdevs_new;
+	}
+
+out:
+	closedir(buses);
+	*_discdevs = discdevs;
+	return r;
+
+}
+
+static int sysfs_scan_device(struct libusb_context *ctx,
+	struct discovered_devs **_discdevs, const char *devname)
+{
+	int busnum;
+	int devaddr;
+
+	usbi_dbg("scan %s", devname);
+
+	busnum = __read_sysfs_attr(ctx, devname, "busnum");
+	if (busnum < 0)
+		return busnum;
+
+	devaddr = __read_sysfs_attr(ctx, devname, "devnum");
+	if (devaddr < 0)
+		return devaddr;
+
+	usbi_dbg("bus=%d dev=%d", busnum, devaddr);
+	if (busnum > 255 || devaddr > 255)
+		return LIBUSB_ERROR_INVALID_PARAM;
+
+	return enumerate_device(ctx, _discdevs, busnum & 0xff, devaddr & 0xff,
+		devname);
+}
+
+static int sysfs_get_device_list(struct libusb_context *ctx,
+	struct discovered_devs **_discdevs)
+{
+	struct discovered_devs *discdevs = *_discdevs;
+	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))) {
+		struct discovered_devs *discdevs_new = discdevs;
+
+		if ((!isdigit(entry->d_name[0]) && strncmp(entry->d_name, "usb", 3))
+				|| strchr(entry->d_name, ':'))
+			continue;
+
+		if (sysfs_scan_device(ctx, &discdevs_new, entry->d_name)) {
+			usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
+			continue;
+		}
+
+		r = 0;
+		discdevs = discdevs_new;
+	}
+
+	if (!r)
+		*_discdevs = discdevs;
+	closedir(devices);
+	return r;
+}
+
+static int op_get_device_list(struct libusb_context *ctx,
+	struct discovered_devs **_discdevs)
+{
+	/* we can retrieve device list and descriptors from sysfs or usbfs.
+	 * sysfs is preferable, because if we use usbfs we end up resuming
+	 * any autosuspended USB devices. however, sysfs is not available
+	 * everywhere, so we need a usbfs fallback too.
+	 *
+	 * as described in the "sysfs vs usbfs" comment 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, _discdevs);
+	else
+		return usbfs_get_device_list(ctx, _discdevs);
+}
+
+static int op_open(struct libusb_device_handle *handle)
+{
+	struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
+	char filename[PATH_MAX];
+
+	_get_usbfs_path(handle->dev, filename);
+	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;
+		}
+	}
+
+	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 r;
+	int i;
+	size_t alloc_size;
+
+	if (tpriv->urbs)
+		return LIBUSB_ERROR_BUSY;
+
+	if (is_out && transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET &&
+	    !supports_flag_zero_packet)
+		return LIBUSB_ERROR_NOT_SUPPORTED;
+
+	/* usbfs places a 16kb limit on bulk URBs. we divide up larger requests
+	 * into smaller units to meet such restriction, then fire off all the
+	 * units at once. it would be simpler if we just fired one unit at a time,
+	 * but there is a big performance gain through doing it this way. */
+	int num_urbs = transfer->length / MAX_BULK_BUFFER_LENGTH;
+	int last_urb_partial = 0;
+
+	if (transfer->length == 0) {
+		num_urbs = 1;
+	} else if ((transfer->length % MAX_BULK_BUFFER_LENGTH) > 0) {
+		last_urb_partial = 1;
+		num_urbs++;
+	}
+	usbi_dbg("need %d urbs for new transfer with length %d", num_urbs,
+		transfer->length);
+	alloc_size = num_urbs * sizeof(struct usbfs_urb);
+	urbs = malloc(alloc_size);
+	if (!urbs)
+		return LIBUSB_ERROR_NO_MEM;
+	memset(urbs, 0, alloc_size);
+	tpriv->urbs = urbs;
+	tpriv->num_urbs = num_urbs;
+	tpriv->num_retired = 0;
+	tpriv->reap_action = NORMAL;
+	tpriv->reap_status = LIBUSB_TRANSFER_COMPLETED;
+
+	for (i = 0; i < num_urbs; i++) {
+		struct usbfs_urb *urb = &urbs[i];
+		urb->usercontext = itransfer;
+		urb->type = urb_type;
+		urb->endpoint = transfer->endpoint;
+		urb->buffer = transfer->buffer + (i * MAX_BULK_BUFFER_LENGTH);
+		if (supports_flag_bulk_continuation && !is_out)
+			urb->flags = USBFS_URB_SHORT_NOT_OK;
+		if (i == num_urbs - 1 && last_urb_partial)
+			urb->buffer_length = transfer->length % MAX_BULK_BUFFER_LENGTH;
+		else if (transfer->length == 0)
+			urb->buffer_length = 0;
+		else
+			urb->buffer_length = MAX_BULK_BUFFER_LENGTH;
+
+		if (i > 0 && supports_flag_bulk_continuation)
+			urb->flags |= USBFS_URB_BULK_CONTINUATION;
+
+		/* 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. */
+
+	/* calculate how many URBs we need */
+	for (i = 0; i < num_packets; i++) {
+		int space_remaining = MAX_ISO_BUFFER_LENGTH - this_urb_len;
+		packet_len = transfer->iso_packet_desc[i].length;
+
+		if (packet_len > space_remaining) {
+			num_urbs++;
+			this_urb_len = packet_len;
+		} else {
+			this_urb_len += packet_len;
+		}
+	}
+	usbi_dbg("need %d 32k URBs for transfer", num_urbs);
+
+	alloc_size = num_urbs * sizeof(*urbs);
+	urbs = malloc(alloc_size);
+	if (!urbs)
+		return LIBUSB_ERROR_NO_MEM;
+	memset(urbs, 0, alloc_size);
+
+	tpriv->iso_urbs = urbs;
+	tpriv->num_urbs = num_urbs;
+	tpriv->num_retired = 0;
+	tpriv->reap_action = NORMAL;
+	tpriv->iso_packet_offset = 0;
+
+	/* allocate + initialize each URB with the correct number of packets */
+	for (i = 0; i < num_urbs; i++) {
+		struct usbfs_urb *urb;
+		int space_remaining_in_urb = MAX_ISO_BUFFER_LENGTH;
+		int urb_packet_offset = 0;
+		unsigned char *urb_buffer_orig = urb_buffer;
+		int j;
+		int k;
+
+		/* swallow up all the packets we can fit into this URB */
+		while (packet_offset < transfer->num_iso_packets) {
+			packet_len = transfer->iso_packet_desc[packet_offset].length;
+			if (packet_len <= space_remaining_in_urb) {
+				/* throw it in */
+				urb_packet_offset++;
+				packet_offset++;
+				space_remaining_in_urb -= packet_len;
+				urb_buffer += packet_len;
+			} else {
+				/* it can't fit, save it for the next URB */
+				break;
+			}
+		}
+
+		alloc_size = sizeof(*urb)
+			+ (urb_packet_offset * sizeof(struct usbfs_iso_packet_desc));
+		urb = malloc(alloc_size);
+		if (!urb) {
+			free_iso_urbs(tpriv);
+			return LIBUSB_ERROR_NO_MEM;
+		}
+		memset(urb, 0, alloc_size);
+		urbs[i] = urb;
+
+		/* populate packet lengths */
+		for (j = 0, k = packet_offset - urb_packet_offset;
+				k < packet_offset; k++, j++) {
+			packet_len = transfer->iso_packet_desc[k].length;
+			urb->iso_frame_desc[j].length = packet_len;
+		}
+
+		urb->usercontext = itransfer;
+		urb->type = USBFS_URB_TYPE_ISO;
+		/* FIXME: interface for non-ASAP data? */
+		urb->flags = USBFS_URB_ISO_ASAP;
+		urb->endpoint = transfer->endpoint;
+		urb->number_of_packets = urb_packet_offset;
+		urb->buffer = urb_buffer_orig;
+	}
+
+	/* submit URBs */
+	for (i = 0; i < num_urbs; i++) {
+		int r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urbs[i]);
+		if (r < 0) {
+			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;
+	int i = 0;
+
+	usbi_mutex_lock(&ctx->open_devs_lock);
+	for (i = 0; i < nfds && num_ready > 0; i++) {
+		struct pollfd *pollfd = &fds[i];
+		struct libusb_device_handle *handle;
+		struct linux_device_handle_priv *hpriv = NULL;
+
+		if (!pollfd->revents)
+			continue;
+
+		num_ready--;
+		list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
+			hpriv = _device_handle_priv(handle);
+			if (hpriv->fd == pollfd->fd)
+				break;
+		}
+
+		if (pollfd->revents & POLLERR) {
+			usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd);
+			usbi_handle_disconnect(handle);
+			continue;
+		}
+
+		r = reap_for_handle(handle);
+		if (r == 1 || r == LIBUSB_ERROR_NO_DEVICE)
+			continue;
+		else if (r < 0)
+			goto out;
+	}
+
+	r = 0;
+out:
+	usbi_mutex_unlock(&ctx->open_devs_lock);
+	return r;
+}
+
+static int op_clock_gettime(int clk_id, struct timespec *tp)
+{
+	switch (clk_id) {
+	case USBI_CLOCK_MONOTONIC:
+		return clock_gettime(monotonic_clkid, tp);
+	case USBI_CLOCK_REALTIME:
+		return clock_gettime(CLOCK_REALTIME, tp);
+	default:
+		return LIBUSB_ERROR_INVALID_PARAM;
+  }
+}
+
+#ifdef USBI_TIMERFD_AVAILABLE
+static clockid_t op_get_timerfd_clockid(void)
+{
+	return monotonic_clkid;
+
+}
+#endif
+
+const struct usbi_os_backend linux_usbfs_backend = {
+	.name = "Linux usbfs",
+	.init = op_init,
+	.exit = NULL,
+	.get_device_list = op_get_device_list,
+	.get_device_descriptor = op_get_device_descriptor,
+	.get_active_config_descriptor = op_get_active_config_descriptor,
+	.get_config_descriptor = op_get_config_descriptor,
+
+	.open = op_open,
+	.close = op_close,
+	.get_configuration = op_get_configuration,
+	.set_configuration = op_set_configuration,
+	.claim_interface = op_claim_interface,
+	.release_interface = op_release_interface,
+
+	.set_interface_altsetting = op_set_interface,
+	.clear_halt = op_clear_halt,
+	.reset_device = op_reset_device,
+
+	.kernel_driver_active = op_kernel_driver_active,
+	.detach_kernel_driver = op_detach_kernel_driver,
+	.attach_kernel_driver = op_attach_kernel_driver,
+
+	.destroy_device = op_destroy_device,
+
+	.submit_transfer = op_submit_transfer,
+	.cancel_transfer = op_cancel_transfer,
+	.clear_transfer_priv = op_clear_transfer_priv,
+
+	.handle_events = op_handle_events,
+
+	.clock_gettime = op_clock_gettime,
+
+#ifdef USBI_TIMERFD_AVAILABLE
+	.get_timerfd_clockid = op_get_timerfd_clockid,
+#endif
+
+	.device_priv_size = sizeof(struct linux_device_priv),
+	.device_handle_priv_size = sizeof(struct linux_device_handle_priv),
+	.transfer_priv_size = sizeof(struct linux_transfer_priv),
+	.add_iso_packet_size = 0,
+};
+
diff --git a/libusb/os/linux_usbfs.h b/libusb/os/linux_usbfs.h
new file mode 100644
index 0000000..487acb5
--- /dev/null
+++ b/libusb/os/linux_usbfs.h
@@ -0,0 +1,139 @@
+/*
+ * usbfs header structures
+ * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBUSB_USBFS_H
+#define LIBUSB_USBFS_H
+
+#define SYSFS_DEVICE_PATH "/sys/bus/usb/devices"
+
+struct usbfs_ctrltransfer {
+	/* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */
+	uint8_t  bmRequestType;
+	uint8_t  bRequest;
+	uint16_t wValue;
+	uint16_t wIndex;
+	uint16_t wLength;
+
+	uint32_t timeout;	/* in milliseconds */
+
+	/* pointer to data */
+	void *data;
+};
+
+struct usbfs_bulktransfer {
+	/* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */
+	unsigned int ep;
+	unsigned int len;
+	unsigned int timeout;	/* in milliseconds */
+
+	/* pointer to data */
+	void *data;
+};
+
+struct usbfs_setinterface {
+	/* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */
+	unsigned int interface;
+	unsigned int altsetting;
+};
+
+#define USBFS_MAXDRIVERNAME 255
+
+struct usbfs_getdriver {
+	unsigned int interface;
+	char driver[USBFS_MAXDRIVERNAME + 1];
+};
+
+#define USBFS_URB_SHORT_NOT_OK		0x01
+#define USBFS_URB_ISO_ASAP			0x02
+#define USBFS_URB_BULK_CONTINUATION	0x04
+#define USBFS_URB_QUEUE_BULK		0x10
+#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 IOCTL_USBFS_CONTROL	_IOWR('U', 0, struct usbfs_ctrltransfer)
+#define IOCTL_USBFS_BULK		_IOWR('U', 2, struct usbfs_bulktransfer)
+#define IOCTL_USBFS_RESETEP	_IOR('U', 3, unsigned int)
+#define IOCTL_USBFS_SETINTF	_IOR('U', 4, struct usbfs_setinterface)
+#define IOCTL_USBFS_SETCONFIG	_IOR('U', 5, unsigned int)
+#define IOCTL_USBFS_GETDRIVER	_IOW('U', 8, struct usbfs_getdriver)
+#define IOCTL_USBFS_SUBMITURB	_IOR('U', 10, struct usbfs_urb)
+#define IOCTL_USBFS_DISCARDURB	_IO('U', 11)
+#define IOCTL_USBFS_REAPURB	_IOW('U', 12, void *)
+#define IOCTL_USBFS_REAPURBNDELAY	_IOW('U', 13, void *)
+#define IOCTL_USBFS_CLAIMINTF	_IOR('U', 15, unsigned int)
+#define IOCTL_USBFS_RELEASEINTF	_IOR('U', 16, unsigned int)
+#define IOCTL_USBFS_CONNECTINFO	_IOW('U', 17, struct usbfs_connectinfo)
+#define IOCTL_USBFS_IOCTL         _IOWR('U', 18, struct usbfs_ioctl)
+#define IOCTL_USBFS_HUB_PORTINFO	_IOR('U', 19, struct usbfs_hub_portinfo)
+#define IOCTL_USBFS_RESET		_IO('U', 20)
+#define IOCTL_USBFS_CLEAR_HALT	_IOR('U', 21, unsigned int)
+#define IOCTL_USBFS_DISCONNECT	_IO('U', 22)
+#define IOCTL_USBFS_CONNECT	_IO('U', 23)
+
+#endif
diff --git a/libusb/os/openbsd_usb.c b/libusb/os/openbsd_usb.c
new file mode 100644
index 0000000..e31941b
--- /dev/null
+++ b/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);
+}
diff --git a/libusb/os/poll_posix.h b/libusb/os/poll_posix.h
new file mode 100644
index 0000000..0e5e7f5
--- /dev/null
+++ b/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 */
diff --git a/libusb/os/poll_windows.c b/libusb/os/poll_windows.c
new file mode 100644
index 0000000..7f4d9c4
--- /dev/null
+++ b/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;
+}
diff --git a/libusb/os/poll_windows.h b/libusb/os/poll_windows.h
new file mode 100644
index 0000000..6e5bf2b
--- /dev/null
+++ b/libusb/os/poll_windows.h
@@ -0,0 +1,115 @@
+/*
+ * Windows compat: POSIX compatibility wrapper
+ * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com>
+ * With contributions from Michael Plante, Orin Eman et al.
+ * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#pragma once
+
+#if defined(_MSC_VER)
+// disable /W4 MSVC warnings that are benign
+#pragma warning(disable:4127) // conditional expression is constant
+#endif
+
+// 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
+
diff --git a/libusb/os/threads_posix.c b/libusb/os/threads_posix.c
new file mode 100644
index 0000000..60c57cf
--- /dev/null
+++ b/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;
+}
diff --git a/libusb/os/threads_posix.h b/libusb/os/threads_posix.h
new file mode 100644
index 0000000..9752208
--- /dev/null
+++ b/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 */
diff --git a/libusb/os/threads_windows.c b/libusb/os/threads_windows.c
new file mode 100644
index 0000000..1394bb0
--- /dev/null
+++ b/libusb/os/threads_windows.c
@@ -0,0 +1,207 @@
+/*
+ * 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);
+		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);
+}
+
diff --git a/libusb/os/threads_windows.h b/libusb/os/threads_windows.h
new file mode 100644
index 0000000..7bb144a
--- /dev/null
+++ b/libusb/os/threads_windows.h
@@ -0,0 +1,86 @@
+/*
+ * libusb synchronization on Microsoft Windows
+ *
+ * Copyright (C) 2010 Michael Plante <michael.plante@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LIBUSB_THREADS_WINDOWS_H
+#define LIBUSB_THREADS_WINDOWS_H
+
+#define usbi_mutex_static_t     volatile LONG
+#define USBI_MUTEX_INITIALIZER  0
+
+#define usbi_mutex_t            HANDLE
+
+struct usbi_cond_perthread {
+	struct list_head list;
+	DWORD            tid;
+	HANDLE           event;
+};
+struct usbi_cond_t_ {
+	// Every time a thread touches the CV, it winds up in one of these lists.
+	//   It stays there until the CV is destroyed, even if the thread
+	//   terminates.
+	struct list_head waiters;
+	struct list_head not_waiting;
+};
+typedef struct usbi_cond_t_ usbi_cond_t;
+
+// We *were* getting timespec from pthread.h:
+#if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED))
+#define HAVE_STRUCT_TIMESPEC 1
+#define _TIMESPEC_DEFINED 1
+struct timespec {
+		long tv_sec;
+		long tv_nsec;
+};
+#endif /* HAVE_STRUCT_TIMESPEC | _TIMESPEC_DEFINED */
+
+// We *were* getting ETIMEDOUT from pthread.h:
+#ifndef ETIMEDOUT
+#  define ETIMEDOUT 10060     /* This is the value in winsock.h. */
+#endif
+
+#define usbi_mutexattr_t void
+#define usbi_condattr_t  void
+
+// 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 */
+
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
new file mode 100644
index 0000000..0739c19
--- /dev/null
+++ b/libusb/os/windows_usb.c
@@ -0,0 +1,2996 @@
+/*
+ * 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 <inttypes.h>
+#include <objbase.h>
+#include <winioctl.h>
+
+#include <libusbi.h>
+#include "poll_windows.h"
+#include "windows_usb.h"
+
+// The following prevents "banned API" errors when using the MS's WDK OACR/Prefast
+#if defined(_PREFAST_)
+#pragma warning(disable:28719)
+#endif
+
+// The 2 macros below are used in conjunction with safe loops.
+#define LOOP_CHECK(fcall) { r=fcall; if (r != LIBUSB_SUCCESS) continue; }
+#define LOOP_BREAK(err) { r=err; continue; }
+
+extern void usbi_fd_notification(struct libusb_context *ctx);
+
+// Helper prototypes
+static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian);
+static int windows_clock_gettime(int clk_id, struct timespec *tp);
+unsigned __stdcall windows_clock_gettime_threaded(void* param);
+// 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_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));
+
+	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));
+
+	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);
+
+	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: %"PRIu64" Hz)", hires_frequency);
+	}
+
+	// Main loop - wait for requests
+	while (1) {
+		timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0;
+		if ( (timer_index != 0) && (timer_index != 1) ) {
+			usbi_dbg("failure to wait on requests: %s", windows_error_str(0));
+			continue;
+		}
+		if (request_count[timer_index] == 0) {
+			// Request already handled
+			ResetEvent(timer_request[timer_index]);
+			// There's still a possiblity that a thread sends a request between the
+			// time we test request_count[] == 0 and we reset the event, in which case
+			// the request would be ignored. The simple solution to that is to test
+			// request_count again and process requests if non zero.
+			if (request_count[timer_index] == 0)
+				continue;
+		}
+		switch (timer_index) {
+		case 0:
+			WaitForSingleObject(timer_mutex, INFINITE);
+			// Requests to this thread are for hires always
+			if (QueryPerformanceCounter(&hires_counter) != 0) {
+				timer_tp.tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
+				timer_tp.tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency)/1000) * hires_ticks_to_ps);
+			} else {
+				// Fallback to real-time if we can't get monotonic value
+				// Note that real-time clock does not wait on the mutex or this thread.
+				windows_clock_gettime(USBI_CLOCK_REALTIME, &timer_tp);
+			}
+			ReleaseMutex(timer_mutex);
+
+			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);
+}
diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h
new file mode 100644
index 0000000..ddbd680
--- /dev/null
+++ b/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));
diff --git a/libusb/sync.c b/libusb/sync.c
new file mode 100644
index 0000000..8eed47b
--- /dev/null
+++ b/libusb/sync.c
@@ -0,0 +1,314 @@
+/*
+ * 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;
+	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;
+	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);
+}
+
diff --git a/libusb/version.h b/libusb/version.h
new file mode 100644
index 0000000..62446da
--- /dev/null
+++ b/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 9
+#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 ""
+#endif
diff --git a/msvc/config.h b/msvc/config.h
new file mode 100644
index 0000000..43aa1f7
--- /dev/null
+++ b/msvc/config.h
@@ -0,0 +1,24 @@
+/* config.h.  Manual config for MSVC.  */
+
+#ifndef _MSC_VER
+#warn "msvc/config.h shouldn't be included for your development environment."
+#error "Please make sure the msvc/ directory is removed from your build path."
+#endif
+
+/* Default visibility */
+#define DEFAULT_VISIBILITY /**/
+
+/* Debug message logging */
+//#define ENABLE_DEBUG_LOGGING 1
+
+/* Message logging */
+#define ENABLE_LOGGING 1
+
+/* Windows backend */
+#define OS_WINDOWS 1
+
+/* type of second poll() argument */
+#define POLL_NFDS_TYPE unsigned int
+
+/* no way to run git describe from MSVC? */
+#define LIBUSB_DESCRIBE ""
diff --git a/msvc/ddk_build.cmd b/msvc/ddk_build.cmd
new file mode 100644
index 0000000..ed9b8a8
--- /dev/null
+++ b/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
diff --git a/msvc/inttypes.h b/msvc/inttypes.h
new file mode 100644
index 0000000..289bb50
--- /dev/null
+++ b/msvc/inttypes.h
@@ -0,0 +1,295 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file was original part of the w64 mingw-runtime package.
+ */
+
+/*
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  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
+
+/* 7.8 Format conversion of integer types <inttypes.h> */
+
+#ifndef _INTTYPES_H_
+#define _INTTYPES_H_
+
+#include <stdint.h>
+
+#ifdef	__cplusplus
+extern	"C"	{
+#endif
+
+typedef struct {
+	intmax_t quot;
+	intmax_t rem;
+	} imaxdiv_t;
+
+
+/* 7.8.1 Macros for format specifiers
+ *
+ * MS runtime does not yet understand C9x standard "ll"
+ * length specifier. It appears to treat "ll" as "l".
+ * The non-standard I64 length specifier causes warning in GCC,
+ * but understood by MS runtime functions.
+ */
+
+/* fprintf macros for signed types */
+#define PRId8 "d"
+#define PRId16 "d"
+#define PRId32 "d"
+#define PRId64 "I64d"
+
+#define PRIdLEAST8 "d"
+#define PRIdLEAST16 "d"
+#define PRIdLEAST32 "d"
+#define PRIdLEAST64 "I64d"
+
+#define PRIdFAST8 "d"
+#define PRIdFAST16 "d"
+#define PRIdFAST32 "d"
+#define PRIdFAST64 "I64d"
+
+#define PRIdMAX "I64d"
+
+#define PRIi8 "i"
+#define PRIi16 "i"
+#define PRIi32 "i"
+#define PRIi64 "I64i"
+
+#define PRIiLEAST8 "i"
+#define PRIiLEAST16 "i"
+#define PRIiLEAST32 "i"
+#define PRIiLEAST64 "I64i"
+
+#define PRIiFAST8 "i"
+#define PRIiFAST16 "i"
+#define PRIiFAST32 "i"
+#define PRIiFAST64 "I64i"
+
+#define PRIiMAX "I64i"
+
+#define PRIo8 "o"
+#define PRIo16 "o"
+#define PRIo32 "o"
+#define PRIo64 "I64o"
+
+#define PRIoLEAST8 "o"
+#define PRIoLEAST16 "o"
+#define PRIoLEAST32 "o"
+#define PRIoLEAST64 "I64o"
+
+#define PRIoFAST8 "o"
+#define PRIoFAST16 "o"
+#define PRIoFAST32 "o"
+#define PRIoFAST64 "I64o"
+
+#define PRIoMAX "I64o"
+
+/* fprintf macros for unsigned types */
+#define PRIu8 "u"
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRIu64 "I64u"
+
+
+#define PRIuLEAST8 "u"
+#define PRIuLEAST16 "u"
+#define PRIuLEAST32 "u"
+#define PRIuLEAST64 "I64u"
+
+#define PRIuFAST8 "u"
+#define PRIuFAST16 "u"
+#define PRIuFAST32 "u"
+#define PRIuFAST64 "I64u"
+
+#define PRIuMAX "I64u"
+
+#define PRIx8 "x"
+#define PRIx16 "x"
+#define PRIx32 "x"
+#define PRIx64 "I64x"
+
+#define PRIxLEAST8 "x"
+#define PRIxLEAST16 "x"
+#define PRIxLEAST32 "x"
+#define PRIxLEAST64 "I64x"
+
+#define PRIxFAST8 "x"
+#define PRIxFAST16 "x"
+#define PRIxFAST32 "x"
+#define PRIxFAST64 "I64x"
+
+#define PRIxMAX "I64x"
+
+#define PRIX8 "X"
+#define PRIX16 "X"
+#define PRIX32 "X"
+#define PRIX64 "I64X"
+
+#define PRIXLEAST8 "X"
+#define PRIXLEAST16 "X"
+#define PRIXLEAST32 "X"
+#define PRIXLEAST64 "I64X"
+
+#define PRIXFAST8 "X"
+#define PRIXFAST16 "X"
+#define PRIXFAST32 "X"
+#define PRIXFAST64 "I64X"
+
+#define PRIXMAX "I64X"
+
+/*
+ *   fscanf macros for signed int types
+ *   NOTE: if 32-bit int is used for int_fast8_t and int_fast16_t
+ *   (see stdint.h, 7.18.1.3), FAST8 and FAST16 should have
+ *   no length identifiers
+ */
+
+#define SCNd16 "hd"
+#define SCNd32 "d"
+#define SCNd64 "I64d"
+
+#define SCNdLEAST16 "hd"
+#define SCNdLEAST32 "d"
+#define SCNdLEAST64 "I64d"
+
+#define SCNdFAST16 "hd"
+#define SCNdFAST32 "d"
+#define SCNdFAST64 "I64d"
+
+#define SCNdMAX "I64d"
+
+#define SCNi16 "hi"
+#define SCNi32 "i"
+#define SCNi64 "I64i"
+
+#define SCNiLEAST16 "hi"
+#define SCNiLEAST32 "i"
+#define SCNiLEAST64 "I64i"
+
+#define SCNiFAST16 "hi"
+#define SCNiFAST32 "i"
+#define SCNiFAST64 "I64i"
+
+#define SCNiMAX "I64i"
+
+#define SCNo16 "ho"
+#define SCNo32 "o"
+#define SCNo64 "I64o"
+
+#define SCNoLEAST16 "ho"
+#define SCNoLEAST32 "o"
+#define SCNoLEAST64 "I64o"
+
+#define SCNoFAST16 "ho"
+#define SCNoFAST32 "o"
+#define SCNoFAST64 "I64o"
+
+#define SCNoMAX "I64o"
+
+#define SCNx16 "hx"
+#define SCNx32 "x"
+#define SCNx64 "I64x"
+
+#define SCNxLEAST16 "hx"
+#define SCNxLEAST32 "x"
+#define SCNxLEAST64 "I64x"
+
+#define SCNxFAST16 "hx"
+#define SCNxFAST32 "x"
+#define SCNxFAST64 "I64x"
+
+#define SCNxMAX "I64x"
+
+/* fscanf macros for unsigned int types */
+
+#define SCNu16 "hu"
+#define SCNu32 "u"
+#define SCNu64 "I64u"
+
+#define SCNuLEAST16 "hu"
+#define SCNuLEAST32 "u"
+#define SCNuLEAST64 "I64u"
+
+#define SCNuFAST16 "hu"
+#define SCNuFAST32 "u"
+#define SCNuFAST64 "I64u"
+
+#define SCNuMAX "I64u"
+
+#ifdef _WIN64
+#define PRIdPTR "I64d"
+#define PRIiPTR "I64i"
+#define PRIoPTR "I64o"
+#define PRIuPTR "I64u"
+#define PRIxPTR "I64x"
+#define PRIXPTR "I64X"
+#define SCNdPTR "I64d"
+#define SCNiPTR "I64i"
+#define SCNoPTR "I64o"
+#define SCNxPTR "I64x"
+#define SCNuPTR "I64u"
+#else
+#define PRIdPTR "d"
+#define PRIiPTR "i"
+#define PRIoPTR "o"
+#define PRIuPTR "u"
+#define PRIxPTR "x"
+#define PRIXPTR "X"
+#define SCNdPTR "d"
+#define SCNiPTR "i"
+#define SCNoPTR "o"
+#define SCNxPTR "x"
+ #define SCNuPTR "u"
+#endif
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+/*
+ * no length modifier for char types prior to C9x
+ * MS runtime  scanf appears to treat "hh" as "h"
+ */
+
+/* signed char */
+#define SCNd8 "hhd"
+#define SCNdLEAST8 "hhd"
+#define SCNdFAST8 "hhd"
+
+#define SCNi8 "hhi"
+#define SCNiLEAST8 "hhi"
+#define SCNiFAST8 "hhi"
+
+#define SCNo8 "hho"
+#define SCNoLEAST8 "hho"
+#define SCNoFAST8 "hho"
+
+#define SCNx8 "hhx"
+#define SCNxLEAST8 "hhx"
+#define SCNxFAST8 "hhx"
+
+/* unsigned char */
+#define SCNu8 "hhu"
+#define SCNuLEAST8 "hhu"
+#define SCNuFAST8 "hhu"
+#endif /* __STDC_VERSION__ >= 199901 */
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* ndef _INTTYPES_H */
diff --git a/msvc/libusb.dsw b/msvc/libusb.dsw
new file mode 100644
index 0000000..8926e67
--- /dev/null
+++ b/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>

+{{{

+}}}

+

+###############################################################################

+

diff --git a/msvc/libusb_dll.dsp b/msvc/libusb_dll.dsp
new file mode 100644
index 0000000..96a011e
--- /dev/null
+++ b/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

diff --git a/msvc/libusb_dll.vcproj b/msvc/libusb_dll.vcproj
new file mode 100644
index 0000000..242898b
--- /dev/null
+++ b/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>

diff --git a/msvc/libusb_dll.vcxproj b/msvc/libusb_dll.vcxproj
new file mode 100644
index 0000000..fe02056
--- /dev/null
+++ b/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>

diff --git a/msvc/libusb_dll.vcxproj.filters b/msvc/libusb_dll.vcxproj.filters
new file mode 100644
index 0000000..1078ae1
--- /dev/null
+++ b/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>

diff --git a/msvc/libusb_sources b/msvc/libusb_sources
new file mode 100644
index 0000000..8e8e65c
--- /dev/null
+++ b/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
diff --git a/msvc/libusb_static.dsp b/msvc/libusb_static.dsp
new file mode 100644
index 0000000..007fcc7
--- /dev/null
+++ b/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

diff --git a/msvc/libusb_static.vcproj b/msvc/libusb_static.vcproj
new file mode 100644
index 0000000..bd0ca52
--- /dev/null
+++ b/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>

diff --git a/msvc/libusb_static.vcxproj b/msvc/libusb_static.vcxproj
new file mode 100644
index 0000000..63fb20b
--- /dev/null
+++ b/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>

diff --git a/msvc/libusb_static.vcxproj.filters b/msvc/libusb_static.vcxproj.filters
new file mode 100644
index 0000000..11fe1fb
--- /dev/null
+++ b/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>

diff --git a/msvc/libusb_vs2005.sln b/msvc/libusb_vs2005.sln
new file mode 100644
index 0000000..6ebb5e6
--- /dev/null
+++ b/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

diff --git a/msvc/libusb_vs2010.sln b/msvc/libusb_vs2010.sln
new file mode 100644
index 0000000..1160f52
--- /dev/null
+++ b/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

diff --git a/msvc/listdevs.dsp b/msvc/listdevs.dsp
new file mode 100644
index 0000000..2ed8aec
--- /dev/null
+++ b/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

diff --git a/msvc/listdevs.vcproj b/msvc/listdevs.vcproj
new file mode 100644
index 0000000..cff754e
--- /dev/null
+++ b/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>

diff --git a/msvc/listdevs.vcxproj b/msvc/listdevs.vcxproj
new file mode 100644
index 0000000..b0164bb
--- /dev/null
+++ b/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>

diff --git a/msvc/listdevs.vcxproj.filters b/msvc/listdevs.vcxproj.filters
new file mode 100644
index 0000000..856fc1c
--- /dev/null
+++ b/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>

diff --git a/msvc/listdevs_sources b/msvc/listdevs_sources
new file mode 100644
index 0000000..97a5723
--- /dev/null
+++ b/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
diff --git a/msvc/stdint.h b/msvc/stdint.h
new file mode 100644
index 0000000..00988d9
--- /dev/null
+++ b/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