Browse Source

Convert libusb-1.0.16-rc10 to libusbx-1.0.17

Con Kolivas 12 years ago
parent
commit
677e9816a5
54 changed files with 6919 additions and 3119 deletions
  1. 31 15
      compat/libusb-1.0/AUTHORS
  2. 196 0
      compat/libusb-1.0/ChangeLog
  3. 13 9
      compat/libusb-1.0/Makefile.am
  4. 2 65
      compat/libusb-1.0/NEWS
  5. 13 14
      compat/libusb-1.0/PORTING
  6. 21 14
      compat/libusb-1.0/README
  7. 0 8
      compat/libusb-1.0/THANKS
  8. 2 9
      compat/libusb-1.0/TODO
  9. 80 28
      compat/libusb-1.0/configure.ac
  10. 1 2
      compat/libusb-1.0/doc/Makefile.am
  11. 16 22
      compat/libusb-1.0/doc/doxygen.cfg.in
  12. 5 1
      compat/libusb-1.0/examples/Makefile.am
  13. 4 5
      compat/libusb-1.0/examples/dpfp.c
  14. 4 5
      compat/libusb-1.0/examples/dpfp_threaded.c
  15. 60 58
      compat/libusb-1.0/examples/hotplugtest.c
  16. 14 7
      compat/libusb-1.0/examples/listdevs.c
  17. 1 1
      compat/libusb-1.0/examples/sam3u_benchmark.c
  18. 0 256
      compat/libusb-1.0/examples/testlibusb1.c
  19. 2 3
      compat/libusb-1.0/libusb-1.0.pc.in
  20. 33 13
      compat/libusb-1.0/libusb/Makefile.am
  21. 346 203
      compat/libusb-1.0/libusb/core.c
  22. 584 257
      compat/libusb-1.0/libusb/descriptor.c
  23. 165 141
      compat/libusb-1.0/libusb/hotplug.c
  24. 18 13
      compat/libusb-1.0/libusb/hotplug.h
  25. 276 221
      compat/libusb-1.0/libusb/io.c
  26. 39 1
      compat/libusb-1.0/libusb/libusb-1.0.def
  27. 9 4
      compat/libusb-1.0/libusb/libusb-1.0.rc
  28. 351 191
      compat/libusb-1.0/libusb/libusb.h
  29. 158 125
      compat/libusb-1.0/libusb/libusbi.h
  30. 317 198
      compat/libusb-1.0/libusb/os/darwin_usb.c
  31. 28 41
      compat/libusb-1.0/libusb/os/darwin_usb.h
  32. 156 42
      compat/libusb-1.0/libusb/os/linux_netlink.c
  33. 127 63
      compat/libusb-1.0/libusb/os/linux_udev.c
  34. 429 500
      compat/libusb-1.0/libusb/os/linux_usbfs.c
  35. 20 7
      compat/libusb-1.0/libusb/os/linux_usbfs.h
  36. 734 0
      compat/libusb-1.0/libusb/os/netbsd_usb.c
  37. 215 119
      compat/libusb-1.0/libusb/os/openbsd_usb.c
  38. 51 0
      compat/libusb-1.0/libusb/os/poll_posix.c
  39. 2 1
      compat/libusb-1.0/libusb/os/poll_posix.h
  40. 92 111
      compat/libusb-1.0/libusb/os/poll_windows.c
  41. 14 6
      compat/libusb-1.0/libusb/os/poll_windows.h
  42. 37 10
      compat/libusb-1.0/libusb/os/threads_posix.c
  43. 4 2
      compat/libusb-1.0/libusb/os/threads_posix.h
  44. 16 12
      compat/libusb-1.0/libusb/os/threads_windows.c
  45. 4 5
      compat/libusb-1.0/libusb/os/threads_windows.h
  46. 1026 0
      compat/libusb-1.0/libusb/os/wince_usb.c
  47. 131 0
      compat/libusb-1.0/libusb/os/wince_usb.h
  48. 108 0
      compat/libusb-1.0/libusb/os/windows_common.h
  49. 323 150
      compat/libusb-1.0/libusb/os/windows_usb.c
  50. 421 111
      compat/libusb-1.0/libusb/os/windows_usb.h
  51. 184 0
      compat/libusb-1.0/libusb/strerror.c
  52. 32 47
      compat/libusb-1.0/libusb/sync.c
  53. 3 3
      compat/libusb-1.0/libusb/version.h
  54. 1 0
      compat/libusb-1.0/libusb/version_nano.h

+ 31 - 15
compat/libusb-1.0/AUTHORS

@@ -1,46 +1,62 @@
-Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
-Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
-Copyright (C) 2008-2013 Nathan Hjelm <hjelmn@users.sourceforge.net>
-Copyright (C) 2009-2012 Pete Batard <pete@akeo.ie>
-Copyright (C) 2010 Michael Plante <michael.plante@gmail.com>
-Copyright (C) 2010-2012 Peter Stuge <peter@stuge.se>
-Copyright (C) 2011-2012 Hans de Goede <hdegoede@redhat.com>
-Copyright (C) 2012 Martin Pieuchot <mpi@openbsd.org>
+Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
+Copyright © 2007-2009 Daniel Drake <dsd@gentoo.org>
+Copyright © 2010-2012 Peter Stuge <peter@stuge.se>
+Copyright © 2008-2013 Nathan Hjelm <hjelmn@users.sourceforge.net>
+Copyright © 2009-2013 Pete Batard <pete@akeo.ie>
+Copyright © 2009-2013 Ludovic Rousseau <ludovic.rousseau@gmail.com>
+Copyright © 2010-2012 Michael Plante <michael.plante@gmail.com>
+Copyright © 2011-2013 Hans de Goede <hdegoede@redhat.com>
+Copyright © 2012-2013 Martin Pieuchot <mpi@openbsd.org>
+Copyright © 2012-2013 Toby Gray <toby.gray@realvnc.com>
 
 
 Other contributors:
 Other contributors:
 Alan Ott
 Alan Ott
 Alan Stern
 Alan Stern
 Alex Vatchenko
 Alex Vatchenko
+Anthony Clay
 Artem Egorkine
 Artem Egorkine
 Aurelien Jarno
 Aurelien Jarno
 Bastien Nocera
 Bastien Nocera
-Brian Shirley
+Benjamin Dobell
+Chris Dickens
+Colin Walters
+Dave Camarillo
 David Engraf
 David Engraf
 David Moore
 David Moore
+Davidlohr Bueso
+Federico Manzan
 Felipe Balbi
 Felipe Balbi
+Florian Albrechtskirchinger
+Francesco Montorsi
 Graeme Gill
 Graeme Gill
-Hans de Goede
 Hans Ulrich Niedermann
 Hans Ulrich Niedermann
 Hector Martin
 Hector Martin
 Hoi-Ho Chan
 Hoi-Ho Chan
+Ilya Konstantinov
 James Hanko
 James Hanko
 Konrad Rzepecki
 Konrad Rzepecki
-Ludovic Rousseau
+Lars Wirzenius
+Luca Longinotti
 Martin Koegler
 Martin Koegler
-Martin Pieuchot
-Maya Erez
+Matthias Bolte
 Mike Frysinger
 Mike Frysinger
 Mikhail Gusarov
 Mikhail Gusarov
+Nicholas Corgan
 Orin Eman
 Orin Eman
+Paul Fertser
 Pekka Nikander
 Pekka Nikander
-Peter Stuge
 Rob Walker
 Rob Walker
 Sean McBride
 Sean McBride
 Sebastian Pipping
 Sebastian Pipping
-Stephan Meyer
+Simon Haggett
 Thomas Röfer
 Thomas Röfer
+Tim Roberts
 Toby Peterson
 Toby Peterson
 Trygve Laugstøl
 Trygve Laugstøl
+Uri Lublin
 Vasily Khoruzhick
 Vasily Khoruzhick
+Vegard Storheil Eriksen
 Vitali Lovich
 Vitali Lovich
 Xiaofan Chen
 Xiaofan Chen
+Zoltán Kovács
+Роман Донченко

+ 196 - 0
compat/libusb-1.0/ChangeLog

@@ -0,0 +1,196 @@
+For detailed information about the changes below, please see the git log or
+visit: http://log.libusbx.org
+
+2013-09-06: v1.0.17
+* Hotplug callbacks now always get passed a libusb_context, even if it is
+  the default context. Previously NULL would be passed for the default context,
+  but since the first context created is the default context, and most apps
+  use only 1 context, this meant that apps explicitly creating a context would
+  still get passed NULL
+* Android: Add .mk files to build with the Android NDK
+* Darwin: Add Xcode project
+* Darwin: Fix crash on unplug (#121)
+* Linux: Fix hang (deadlock) on libusb_exit
+* Linux: Fix libusbx build failure with --disable-udev (#124)
+* Linux: Fix libusb_get_device_list() hang with --disable-udev (#130)
+* OpenBSD: Update OpenBSD backend with support for control transfers to
+  non-ugen(4) devices and make get_configuration() no longer generate I/O.
+  Note that using this libusbx version on OpenBSD requires using
+  OpenBSD 5.3-current or later. Users of older OpenBSD versions are advised
+  to stay with the libusb shipped with OpenBSD (mpi)
+* Windows: fix libusb_dll_2010.vcxproj link errors (#129)
+* Various other bug fixes and improvements
+The (#xx) numbers are libusbx issue numbers, see ie:
+https://github.com/libusbx/libusbx/issues/121
+
+2013-07-11: v1.0.16
+* Add hotplug support for Darwin and Linux (#9)
+* Add superspeed endpoint companion descriptor support (#15)
+* Add BOS descriptor support (#15)
+* Make descriptor parsing code more robust
+* New libusb_get_port_numbers API, this is libusb_get_port_path without
+  the unnecessary context parameter, libusb_get_port_path is now deprecated
+* New libusb_strerror API (#14)
+* New libusb_set_auto_detach_kernel_driver API (#17)
+* Improve topology API docs (#95)
+* Logging now use a single write call per log-message, avoiding log-message
+  "interlacing" when using multiple threads.
+* Android: use Android logging when building on Android (#101)
+* Darwin: make libusb_reset reenumerate device on descriptors change (#89)
+* Darwin: add support for the LIBUSB_TRANSFER_ADD_ZERO_PACKET flag (#91)
+* Darwin: add a device cache (#112, #114)
+* Examples: Add sam3u_benchmark isochronous example by Harald Welte (#109)
+* Many other bug fixes and improvements
+The (#xx) numbers are libusbx issue numbers, see ie:
+https://github.com/libusbx/libusbx/issues/9
+
+2013-04-15: v1.0.15
+* Improve transfer cancellation and avoid short read failures on broken descriptors
+* Filter out 8-bit characters in libusb_get_string_descriptor_ascii()
+* Add WinCE support
+* Add library stress tests
+* Add Cypress FX3 firmware upload support for fxload sample
+* Add HID and kernel driver detach support capabilities detection
+* Add SuperSpeed detection on OS X
+* Fix bInterval value interpretation on OS X
+* Fix issues with autoclaim, composite HID devices, interface autoclaim and
+  early abort in libusb_close() on Windows. Also add VS2012 solution files.
+* Improve fd event handling on Linux
+* Other bug fixes and improvements
+
+2012-09-26: v1.0.14
+* Reverts the previous API change with regards to bMaxPower.
+  If this doesn't matter to you, you are encouraged to keep using v1.0.13,
+  as it will use the same attribute as v2.0, to be released soon.
+* Note that LIBUSBX_API_VERSION is *decreased* to 0x010000FF and the previous
+  guidelines with regards to concurrent use of MaxPower/bMaxPower still apply.
+
+2012-09-20: v1.0.13
+* [MAJOR] Fix a typo in the API with struct libusb_config_descriptor where
+  MaxPower was used instead of bMaxPower, as defined in the specs. If your 
+  application was accessing the MaxPower attribute, and you need to maintain
+  compatibility with libusb or older versions, see APPENDIX A below.
+* Fix broken support for the 0.1 -> 1.0 libusb-compat layer
+* Fix unwanted cancellation of pending timeouts as well as major timeout related bugs
+* Fix handling of HID and composite devices on Windows
+* Introduce LIBUSBX_API_VERSION macro
+* Add Cypress FX/FX2 firmware upload sample, based on fxload from
+  http://linux-hotplug.sourceforge.net
+* Add libusb0 (libusb-win32) and libusbK driver support on Windows. Note that while
+  the drivers allow it, isochronous transfers are not supported yet in libusbx. Also
+  not supported yet is the use of libusb-win32 filter drivers on composite interfaces
+* Add support for the new get_capabilities ioctl on Linux and avoid unnecessary
+  splitting of bulk transfers
+* Improve support for newer Intel and Renesas USB 3.0 controllers on Windows
+* Harmonize the device number for root hubs across platforms
+* Other bug fixes and improvements
+
+2012-06-15: v1.0.12
+* Fix a potential major regression with pthread on Linux
+* Fix missing thread ID from debug log output on cygwin
+* Fix possible crash when using longjmp and MinGW's gcc 4.6
+* Add topology calls: libusb_get_port_number(), libusb_get_parent() & libusb_get_port_path()
+* Add toggleable debug, using libusb_set_debug() or the LIBUSB_DEBUG environment variable
+* Define log levels in libusb.h and set timestamp origin to first libusb_init() call
+* All logging is now sent to to stderr (info was sent to stdout previously)
+* Update log messages severity and avoid polluting log output on OS-X
+* Add HID driver support on Windows
+* Enable interchangeability of MSVC and MinGW DLLs
+* Additional bug fixes and improvements
+
+2012-05-08: v1.0.11
+* Revert removal of critical Windows event handling that was introduced in 1.0.10
+* Fix a possible deadlock in Windows when submitting transfers
+* Add timestamped logging
+* Add NetBSD support (experimental) and BSD libusb_get_device_speed() data
+* Add bootstrap.sh alongside autogen.sh (bootstrap.sh doesn't invoke configure)
+* Search for device nodes in /dev for Android support
+* Other bug fixes
+
+2012-04-17: v1.0.10
+* Public release
+* Add libusb_get_version
+* Add Visual Studio 2010 project files
+* Some Windows code cleanup
+* Fix xusb sample warnings 
+
+2012-04-02: v1.0.9
+* First libusbx release
+* Add libusb_get_device_speed (all, except BSD) and libusb_error_name
+* Add Windows support (WinUSB driver only)
+* Add OpenBSD support
+* Add xusb sample
+* Tons of bug fixes
+
+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
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+APPENDIX A - How to maintain code compatibility with versions of libusb and
+libusbx that use MaxPower:
+
+If you must to maintain compatibility with versions of the library that aren't
+using the bMaxPower attribute in struct libusb_config_descriptor, the 
+recommended way is to use the new LIBUSBX_API_VERSION macro with an #ifdef.
+For instance, if your code was written as follows:
+
+  if (dev->config[0].MaxPower < 250)
+
+Then you should modify it to have:
+
+#if defined(LIBUSBX_API_VERSION) && (LIBUSBX_API_VERSION >= 0x01000100)
+  if (dev->config[0].bMaxPower < 250)
+#else
+  if (dev->config[0].MaxPower < 250)
+#endif

+ 13 - 9
compat/libusb-1.0/Makefile.am

@@ -1,18 +1,23 @@
 AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip
 AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip
 ACLOCAL_AMFLAGS = -I m4
 ACLOCAL_AMFLAGS = -I m4
 DISTCLEANFILES = libusb-1.0.pc
 DISTCLEANFILES = libusb-1.0.pc
-MAINTAINERCLEANFILES = ChangeLog
-EXTRA_DIST = TODO PORTING
-SUBDIRS = libusb
+EXTRA_DIST = TODO PORTING msvc libusb/libusb-1.0.def libusb/version_nano.h \
+  examples/getopt/getopt.c examples/getopt/getopt1.c examples/getopt/getopt.h \
+  android Xcode
+SUBDIRS = libusb doc
+
+if BUILD_EXAMPLES
+SUBDIRS += examples
+endif
+
+if BUILD_TESTS
+SUBDIRS += tests
+endif
 
 
 pkgconfigdir=$(libdir)/pkgconfig
 pkgconfigdir=$(libdir)/pkgconfig
 pkgconfig_DATA=libusb-1.0.pc
 pkgconfig_DATA=libusb-1.0.pc
 
 
-.PHONY: ChangeLog dist-up
-ChangeLog:
-	git --git-dir $(top_srcdir)/.git log > ChangeLog || touch ChangeLog
-
-dist-hook: ChangeLog
+.PHONY: dist-up
 
 
 reldir = .release/$(distdir)
 reldir = .release/$(distdir)
 dist-up: dist
 dist-up: dist
@@ -21,4 +26,3 @@ dist-up: dist
 	cp $(distdir).tar.bz2 $(reldir)
 	cp $(distdir).tar.bz2 $(reldir)
 	rsync -rv $(reldir) frs.sourceforge.net:/home/frs/project/l/li/libusb/libusb-1.0/
 	rsync -rv $(reldir) frs.sourceforge.net:/home/frs/project/l/li/libusb/libusb-1.0/
 	rm -rf $(reldir)
 	rm -rf $(reldir)
-

+ 2 - 65
compat/libusb-1.0/NEWS

@@ -1,65 +1,2 @@
-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
-
+For the latest libusbx news, please refer to the ChangeLog file, or visit:
+http://libusbx.org

+ 13 - 14
compat/libusb-1.0/PORTING

@@ -1,15 +1,15 @@
-PORTING LIBUSB TO OTHER PLATFORMS
+PORTING LIBUSBX TO OTHER PLATFORMS
 
 
 Introduction
 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
+This document is aimed at developers wishing to port libusbx to unsupported
+platforms. I believe the libusbx API is OS-independent, so by supporting
 multiple operating systems we pave the way for cross-platform USB device
 multiple operating systems we pave the way for cross-platform USB device
 drivers.
 drivers.
 
 
 Implementation-wise, the basic idea is that you provide an interface to
 Implementation-wise, the basic idea is that you provide an interface to
-libusb's internal "backend" API, which performs the appropriate operations on
+libusbx's internal "backend" API, which performs the appropriate operations on
 your target platform.
 your target platform.
 
 
 In terms of USB I/O, your backend provides functionality to submit
 In terms of USB I/O, your backend provides functionality to submit
@@ -27,16 +27,16 @@ e.g. setting configuration, obtaining descriptors, etc.
 File descriptors for I/O polling
 File descriptors for I/O polling
 ================================
 ================================
 
 
-For libusb to work, your event handling function obviously needs to be called
+For libusbx 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
 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
+which libusbx and its users can pass to poll() or select() to determine when
 it is time to call the event handling function.
 it is time to call the event handling function.
 
 
 On Linux, this is easy: the usbfs kernel interface exposes a file descriptor
 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
 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
 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
 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.
+descriptor of the pipe can then be provided to libusbx as an event source.
 
 
 
 
 Interface semantics and documentation
 Interface semantics and documentation
@@ -46,7 +46,7 @@ Documentation of the backend interface can be found in libusbi.h inside the
 usbi_os_backend structure definition.
 usbi_os_backend structure definition.
 
 
 Your implementations of these functions will need to call various internal
 Your implementations of these functions will need to call various internal
-libusb functions, prefixed with "usbi_". Documentation for these functions
+libusbx functions, prefixed with "usbi_". Documentation for these functions
 can be found in the .c files where they are implemented.
 can be found in the .c files where they are implemented.
 
 
 You probably want to skim over *all* the documentation before starting your
 You probably want to skim over *all* the documentation before starting your
@@ -72,18 +72,18 @@ right usbi_backend for your platform.
 
 
 4. Produce and test your implementation.
 4. Produce and test your implementation.
 
 
-5. Send your implementation to libusb-devel mailing list.
+5. Send your implementation to libusbx-devel mailing list.
 
 
 
 
 Implementation difficulties? Questions?
 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
+If you encounter difficulties porting libusbx to your platform, please raise
+these issues on the libusbx-devel mailing list. Where possible and sensible, I
+am interested in solving problems preventing libusbx from operating on other
 platforms.
 platforms.
 
 
-The libusb-devel mailing list is also a good place to ask questions and
+The libusbx-devel mailing list is also a good place to ask questions and
 make suggestions about the internal API. Hopefully we can produce some
 make suggestions about the internal API. Hopefully we can produce some
 better documentation based on your questions and other input.
 better documentation based on your questions and other input.
 
 
@@ -92,4 +92,3 @@ some infrastructure additions/modifications to better support your platform,
 you are encouraged to make such changes (in cleanly distinct patch
 you are encouraged to make such changes (in cleanly distinct patch
 submissions). Even if you do not make such changes yourself, please do raise
 submissions). Even if you do not make such changes yourself, please do raise
 the issues on the mailing list at the very minimum.
 the issues on the mailing list at the very minimum.
-

+ 21 - 14
compat/libusb-1.0/README

@@ -1,22 +1,29 @@
-libusb
-======
+libusbx
+=======
 
 
-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).
+libusbx is a library for USB device access from Linux, Mac OS X,
+Windows and OpenBSD/NetBSD userspace, with OpenBSD/NetBSD, and to a
+lesser extent some of the newest features of Windows (such as libusbK
+and libusb-win32 driver support) being EXPERIMENTAL.
+It is written in C and licensed under the GNU Lesser General Public
+License version 2.1 or, at your option, any later version (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. :)
+libusbx is abstracted internally in such a way that it can hopefully
+be ported to other operating systems. Please see the PORTING file
+for more information.
 
 
-libusb homepage:
-http://libusb.org/
+libusbx homepage:
+http://libusbx.org/
 
 
 Developers will wish to consult the API documentation:
 Developers will wish to consult the API documentation:
-http://libusb.sourceforge.net/api-1.0/
+http://api.libusbx.org
 
 
 Use the mailing list for questions, comments, etc:
 Use the mailing list for questions, comments, etc:
-http://libusb.org/wiki/MailingList
+http://mailing-list.libusbx.org
 
 
-- Peter Stuge <peter@stuge.se>
-(use the mailing list rather than mailing developers directly)
+- Pete Batard <pete@akeo.ie>
+- Hans de Goede <hdegoede@redhat.com>
+- Xiaofan Chen <xiaofanc@gmail.com>
+- Ludovic Rousseau <ludovic.rousseau@gmail.com>
+- Nathan Hjelm <hjelmn@users.sourceforge.net>
+(Please use the mailing list rather than mailing developers directly)

+ 0 - 8
compat/libusb-1.0/THANKS

@@ -1,8 +0,0 @@
-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

+ 2 - 9
compat/libusb-1.0/TODO

@@ -1,9 +1,2 @@
-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
+Please see the libusbx roadmap by visiting:
+https://github.com/libusbx/libusbx/issues/milestones?direction=asc&sort=due_date

+ 80 - 28
compat/libusb-1.0/configure.ac

@@ -8,25 +8,25 @@ m4_define([LU_DEFINE_VERSION_RC_ATOM],
 	[^#define\s*$1\s*"\(-rc[0-9]*\)".*], [\1]))])
 	[^#define\s*$1\s*"\(-rc[0-9]*\)".*], [\1]))])
 dnl The m4_bregexp() returns (only) the numbers following the #define named
 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 the first macro parameter. m4_define() then defines the name for use
-dnl in AC_INIT().
+dnl in AC_INIT.
 
 
 LU_DEFINE_VERSION_ATOM([LIBUSB_MAJOR])
 LU_DEFINE_VERSION_ATOM([LIBUSB_MAJOR])
 LU_DEFINE_VERSION_ATOM([LIBUSB_MINOR])
 LU_DEFINE_VERSION_ATOM([LIBUSB_MINOR])
 LU_DEFINE_VERSION_ATOM([LIBUSB_MICRO])
 LU_DEFINE_VERSION_ATOM([LIBUSB_MICRO])
 LU_DEFINE_VERSION_RC_ATOM([LIBUSB_RC])
 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/])
+AC_INIT([libusbx],[LIBUSB_MAJOR[.]LIBUSB_MINOR[.]LIBUSB_MICRO[]LIBUSB_RC],[libusbx-devel@lists.sourceforge.net],[libusbx],[http://libusbx.org])
 
 
 # Library versioning
 # Library versioning
 # These numbers should be tweaked on every release. Read carefully:
 # These numbers should be tweaked on every release. Read carefully:
 # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
 # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
 # http://sourceware.org/autobook/autobook/autobook_91.html
 # http://sourceware.org/autobook/autobook/autobook_91.html
-lt_current="2"
+lt_current="1"
 lt_revision="0"
 lt_revision="0"
-lt_age="0"
+lt_age="1"
 LTLDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age}"
 LTLDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age}"
 
 
-AM_INIT_AUTOMAKE([foreign subdir-objects])
+AM_INIT_AUTOMAKE
 AM_MAINTAINER_MODE
 AM_MAINTAINER_MODE
 
 
 AC_CONFIG_SRCDIR([libusb/core.c])
 AC_CONFIG_SRCDIR([libusb/core.c])
@@ -36,7 +36,7 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 
 
 AC_PREREQ([2.50])
 AC_PREREQ([2.50])
 AC_PROG_CC
 AC_PROG_CC
-AC_PROG_LIBTOOL
+LT_INIT
 LT_LANG([Windows Resource])
 LT_LANG([Windows Resource])
 AC_C_INLINE
 AC_C_INLINE
 AM_PROG_CC_C_O
 AM_PROG_CC_C_O
@@ -45,26 +45,34 @@ AC_DEFINE([_GNU_SOURCE], 1, [Use GNU extensions])
 LTLDFLAGS="${LTLDFLAGS} -no-undefined"
 LTLDFLAGS="${LTLDFLAGS} -no-undefined"
 
 
 AC_MSG_CHECKING([operating system])
 AC_MSG_CHECKING([operating system])
+
 case $host in
 case $host in
 *-linux*)
 *-linux*)
 	AC_MSG_RESULT([Linux])
 	AC_MSG_RESULT([Linux])
 	backend="linux"
 	backend="linux"
+	threads="posix"
 	;;
 	;;
 *-darwin*)
 *-darwin*)
 	AC_MSG_RESULT([Darwin/Mac OS X])
 	AC_MSG_RESULT([Darwin/Mac OS X])
 	backend="darwin"
 	backend="darwin"
+	threads="posix"
 	;;
 	;;
 *-openbsd*)
 *-openbsd*)
 	AC_MSG_RESULT([OpenBSD])
 	AC_MSG_RESULT([OpenBSD])
 	backend="openbsd"
 	backend="openbsd"
+	threads="posix"
 	;;
 	;;
 *-netbsd*)
 *-netbsd*)
-	AC_MSG_RESULT([NetBSD (using OpenBSD backend)])
-	backend="openbsd"
+	AC_MSG_RESULT([NetBSD])
+	backend="netbsd"
+	threads="posix"
 	;;
 	;;
 *-mingw*)
 *-mingw*)
 	AC_MSG_RESULT([Windows])
 	AC_MSG_RESULT([Windows])
 	backend="windows"
 	backend="windows"
+	threads="windows"
+	create_import_lib="yes"
+	AM_CFLAGS="${AM_CFLAGS} -fno-omit-frame-pointer"
 	;;
 	;;
 *-cygwin*)
 *-cygwin*)
 	AC_MSG_RESULT([Cygwin (using Windows backend)])
 	AC_MSG_RESULT([Cygwin (using Windows backend)])
@@ -74,24 +82,32 @@ case $host in
 *)
 *)
 	AC_MSG_ERROR([unsupported operating system])
 	AC_MSG_ERROR([unsupported operating system])
 esac
 esac
+
 case $backend in
 case $backend in
 linux)
 linux)
 	AC_DEFINE(OS_LINUX, 1, [Linux backend])
 	AC_DEFINE(OS_LINUX, 1, [Linux backend])
 	AC_SUBST(OS_LINUX)
 	AC_SUBST(OS_LINUX)
-	AC_CHECK_LIB(rt, clock_gettime, -pthread)
+	AC_SEARCH_LIBS(clock_gettime, rt, [], [], -pthread)
 	AC_ARG_ENABLE([udev],
 	AC_ARG_ENABLE([udev],
-                      [AC_HELP_STRING([--with-udev], [use udev for device enumeration and hotplug support (recommended, default: yes)])],
-                      [], [enable_udev="yes"])
-        if test "x$enable_udev" = "xyes" ; then
-                # system has udev. use it or fail!
-                AC_CHECK_HEADERS([libudev.h],[],[AC_ERROR(["udev support requested but libudev not installed"])])
-                AC_CHECK_LIB([udev], [udev_new], [], [AC_ERROR(["udev support requested but libudev not installed"])])
-                AC_DEFINE(USE_UDEV, 1, [Use udev for device enumeration/hotplug])
-        else
-                AC_CHECK_HEADERS([linux/netlink.h linux/filter.h], [], [AC_ERROR(["Linux netlink headers not found"])])
-        fi
-        AC_SUBST(USE_UDEV)
-	threads="posix"
+		[AC_HELP_STRING([--enable-udev], [use udev for device enumeration and hotplug support (recommended) [default=yes]])],
+		[], [enable_udev="yes"])
+		if test "x$enable_udev" = "xyes" ; then
+			# system has udev. use it or fail!
+			AC_CHECK_HEADERS([libudev.h],[],[AC_ERROR(["udev support requested but libudev not installed"])])
+			AC_CHECK_LIB([udev], [udev_new], [], [AC_ERROR(["udev support requested but libudev not installed"])])
+			AC_DEFINE(USE_UDEV, 1, [Use udev for device enumeration/hotplug])
+		else
+			AC_CHECK_HEADERS([asm/types.h sys/socket.h], [], [])
+			AC_CHECK_HEADERS([linux/netlink.h linux/filter.h], [], [AC_ERROR(["Linux netlink headers not found"])], [
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+])
+		fi
+		AC_SUBST(USE_UDEV)
 	THREAD_CFLAGS="-pthread"
 	THREAD_CFLAGS="-pthread"
 	LIBS="${LIBS} -pthread"
 	LIBS="${LIBS} -pthread"
 	AC_CHECK_HEADERS([poll.h])
 	AC_CHECK_HEADERS([poll.h])
@@ -100,7 +116,6 @@ linux)
 darwin)
 darwin)
 	AC_DEFINE(OS_DARWIN, 1, [Darwin backend])
 	AC_DEFINE(OS_DARWIN, 1, [Darwin backend])
 	AC_SUBST(OS_DARWIN)
 	AC_SUBST(OS_DARWIN)
-	threads="posix"
 	LIBS="-lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation"
 	LIBS="-lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation"
 	LTLDFLAGS="${LTLDFLAGS} -Wl,-prebind"
 	LTLDFLAGS="${LTLDFLAGS} -Wl,-prebind"
 	AC_CHECK_HEADERS([poll.h])
 	AC_CHECK_HEADERS([poll.h])
@@ -112,7 +127,14 @@ darwin)
 openbsd)
 openbsd)
 	AC_DEFINE(OS_OPENBSD, 1, [OpenBSD backend])
 	AC_DEFINE(OS_OPENBSD, 1, [OpenBSD backend])
 	AC_SUBST(OS_OPENBSD)
 	AC_SUBST(OS_OPENBSD)
-	threads="posix"
+	THREAD_CFLAGS="-pthread"
+	LIBS="-pthread"
+	AC_CHECK_HEADERS([poll.h])
+	AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
+	;;
+netbsd)
+	AC_DEFINE(OS_NETBSD, 1, [NetBSD backend])
+	AC_SUBST(OS_NETBSD)
 	THREAD_CFLAGS="-pthread"
 	THREAD_CFLAGS="-pthread"
 	LIBS="-pthread"
 	LIBS="-pthread"
 	AC_CHECK_HEADERS([poll.h])
 	AC_CHECK_HEADERS([poll.h])
@@ -126,13 +148,16 @@ windows)
 	AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])
 	AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])
 	;;
 	;;
 esac
 esac
+
 AC_SUBST(LIBS)
 AC_SUBST(LIBS)
 
 
 AM_CONDITIONAL(OS_LINUX, test "x$backend" = xlinux)
 AM_CONDITIONAL(OS_LINUX, test "x$backend" = xlinux)
 AM_CONDITIONAL(OS_DARWIN, test "x$backend" = xdarwin)
 AM_CONDITIONAL(OS_DARWIN, test "x$backend" = xdarwin)
 AM_CONDITIONAL(OS_OPENBSD, test "x$backend" = xopenbsd)
 AM_CONDITIONAL(OS_OPENBSD, test "x$backend" = xopenbsd)
+AM_CONDITIONAL(OS_NETBSD, test "x$backend" = xnetbsd)
 AM_CONDITIONAL(OS_WINDOWS, test "x$backend" = xwindows)
 AM_CONDITIONAL(OS_WINDOWS, test "x$backend" = xwindows)
 AM_CONDITIONAL(THREADS_POSIX, test "x$threads" = xposix)
 AM_CONDITIONAL(THREADS_POSIX, test "x$threads" = xposix)
+AM_CONDITIONAL(CREATE_IMPORT_LIB, test "x$create_import_lib" = "xyes")
 AM_CONDITIONAL(USE_UDEV, test "x$enable_udev" = xyes)
 AM_CONDITIONAL(USE_UDEV, test "x$enable_udev" = xyes)
 if test "$threads" = posix; then
 if test "$threads" = posix; then
 	AC_DEFINE(THREADS_POSIX, 1, [Use POSIX Threads])
 	AC_DEFINE(THREADS_POSIX, 1, [Use POSIX Threads])
@@ -142,7 +167,7 @@ fi
 AC_CHECK_HEADER([sys/timerfd.h], [timerfd_h=1], [timerfd_h=0])
 AC_CHECK_HEADER([sys/timerfd.h], [timerfd_h=1], [timerfd_h=0])
 AC_ARG_ENABLE([timerfd],
 AC_ARG_ENABLE([timerfd],
 	[AS_HELP_STRING([--enable-timerfd],
 	[AS_HELP_STRING([--enable-timerfd],
-		[use timerfd for timing (default auto)])],
+		[use timerfd for timing [default=auto]])],
 	[use_timerfd=$enableval], [use_timerfd='auto'])
 	[use_timerfd=$enableval], [use_timerfd='auto'])
 
 
 if test "x$use_timerfd" = "xyes" -a "x$timerfd_h" = "x0"; then
 if test "x$use_timerfd" = "xyes" -a "x$timerfd_h" = "x0"; then
@@ -177,20 +202,42 @@ if test "x$log_enabled" != "xno"; then
 fi
 fi
 
 
 AC_ARG_ENABLE([debug-log], [AS_HELP_STRING([--enable-debug-log],
 AC_ARG_ENABLE([debug-log], [AS_HELP_STRING([--enable-debug-log],
-	[enable debug logging (default n)])],
+	[start with debug message logging enabled [default=no]])],
 	[debug_log_enabled=$enableval],
 	[debug_log_enabled=$enableval],
 	[debug_log_enabled='no'])
 	[debug_log_enabled='no'])
 if test "x$debug_log_enabled" != "xno"; then
 if test "x$debug_log_enabled" != "xno"; then
-	AC_DEFINE([ENABLE_DEBUG_LOGGING], 1, [Debug message logging])
+	AC_DEFINE([ENABLE_DEBUG_LOGGING], 1, [Start with debug message logging enabled])
+fi
+
+AC_ARG_ENABLE([system-log], [AS_HELP_STRING([--enable-system-log],
+	[output logging messages to system wide log, if supported by the OS [default=no]])],
+	[system_log_enabled=$enableval],
+	[system_log_enabled='no'])
+if test "x$system_log_enabled" != "xno"; then
+	AC_DEFINE([USE_SYSTEM_LOGGING_FACILITY], 1, [Enable output to system log])
+fi
+
+# Check if syslog is available in standard C library
+AC_CHECK_HEADERS(syslog.h)
+AC_CHECK_FUNC([syslog], [have_syslog=yes], [have_syslog=no])
+if test "x$have_syslog" != "xno"; then
+	AC_DEFINE([HAVE_SYSLOG_FUNC], 1, [syslog() function available])
 fi
 fi
 
 
 # Examples build
 # Examples build
 AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build],
 AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build],
-	[build example applications (default n)])],
+	[build example applications [default=no]])],
 	[build_examples=$enableval],
 	[build_examples=$enableval],
 	[build_examples='no'])
 	[build_examples='no'])
 AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != "xno"])
 AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != "xno"])
 
 
+# Tests build
+AC_ARG_ENABLE([tests-build], [AS_HELP_STRING([--enable-tests-build],
+	[build test applications [default=no]])],
+	[build_tests=$enableval],
+	[build_tests='no'])
+AM_CONDITIONAL([BUILD_TESTS], [test "x$build_tests" != "xno"])
+
 # check for -fvisibility=hidden compiler support (GCC >= 3.4)
 # check for -fvisibility=hidden compiler support (GCC >= 3.4)
 saved_cflags="$CFLAGS"
 saved_cflags="$CFLAGS"
 # -Werror required for cygwin
 # -Werror required for cygwin
@@ -217,8 +264,9 @@ AM_CONDITIONAL([HAVE_SIGACTION], [test "x$have_sigaction" = "xyes"])
 # headers not available on all platforms but required on others
 # headers not available on all platforms but required on others
 AC_CHECK_HEADERS([sys/time.h])
 AC_CHECK_HEADERS([sys/time.h])
 AC_CHECK_FUNCS(gettimeofday)
 AC_CHECK_FUNCS(gettimeofday)
+AC_CHECK_HEADERS([signal.h])
 
 
-AM_CFLAGS="-std=gnu99 -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow ${THREAD_CFLAGS} ${VISIBILITY_CFLAGS}"
+AM_CFLAGS="${AM_CFLAGS} -std=gnu99 -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow ${THREAD_CFLAGS} ${VISIBILITY_CFLAGS}"
 
 
 AC_SUBST(AM_CFLAGS)
 AC_SUBST(AM_CFLAGS)
 AC_SUBST(LTLDFLAGS)
 AC_SUBST(LTLDFLAGS)
@@ -226,4 +274,8 @@ AC_SUBST(LTLDFLAGS)
 AC_CONFIG_FILES([libusb-1.0.pc])
 AC_CONFIG_FILES([libusb-1.0.pc])
 AC_CONFIG_FILES([Makefile])
 AC_CONFIG_FILES([Makefile])
 AC_CONFIG_FILES([libusb/Makefile])
 AC_CONFIG_FILES([libusb/Makefile])
+AC_CONFIG_FILES([examples/Makefile])
+AC_CONFIG_FILES([tests/Makefile])
+AC_CONFIG_FILES([doc/Makefile])
+AC_CONFIG_FILES([doc/doxygen.cfg])
 AC_OUTPUT
 AC_OUTPUT

+ 1 - 2
compat/libusb-1.0/doc/Makefile.am

@@ -5,6 +5,5 @@ docs: doxygen.cfg
 
 
 docs-upload: docs
 docs-upload: docs
 	ln -s html api-1.0
 	ln -s html api-1.0
-	rsync -av api-1.0/ web.sourceforge.net:htdocs/api-1.0/
+	scp -r api-1.0 pbatard@web.sourceforge.net:/home/project-web/libusbx/htdocs
 	rm -f api-1.0
 	rm -f api-1.0
-

+ 16 - 22
compat/libusb-1.0/doc/doxygen.cfg.in

@@ -25,13 +25,26 @@ DOXYFILE_ENCODING      = UTF-8
 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
 # by quotes) that should identify the project.
 # by quotes) that should identify the project.
 
 
-PROJECT_NAME           = libusb
+PROJECT_NAME           =
 
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number. 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number. 
 # This could be handy for archiving the generated documentation or 
 # This could be handy for archiving the generated documentation or 
 # if some version control system is used.
 # if some version control system is used.
 
 
-PROJECT_NUMBER         = 
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "eXpand your USB potential"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will
+# copy the logo to the output directory.
+
+PROJECT_LOGO           = libusbx.png
 
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
 # base path where the generated documentation will be put. 
 # base path where the generated documentation will be put. 
@@ -154,13 +167,6 @@ QT_AUTOBRIEF           = NO
 
 
 MULTILINE_CPP_IS_BRIEF = NO
 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 
 # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
 # member inherits the documentation from any documented member that it 
 # member inherits the documentation from any documented member that it 
 # re-implements.
 # re-implements.
@@ -401,12 +407,6 @@ MAX_INITIALIZER_LINES  = 30
 
 
 SHOW_USED_FILES        = YES
 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 
 # 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 
 # 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 
 # version control system). Doxygen will invoke the program by executing (via 
@@ -424,7 +424,7 @@ FILE_VERSION_FILTER    =
 # The QUIET tag can be used to turn on/off the messages that are generated 
 # 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.
 # by doxygen. Possible values are YES and NO. If left blank NO is used.
 
 
-QUIET                  = NO
+QUIET                  = YES
 
 
 # The WARNINGS tag can be used to turn on/off the warning messages that are 
 # 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 
 # generated by doxygen. Possible values are YES and NO. If left blank 
@@ -701,12 +701,6 @@ HTML_FOOTER            =
 
 
 HTML_STYLESHEET        = 
 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 
 # 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 
 # 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) 
 # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 

+ 5 - 1
compat/libusb-1.0/examples/Makefile.am

@@ -1,6 +1,7 @@
 AM_CPPFLAGS = -I$(top_srcdir)/libusb
 AM_CPPFLAGS = -I$(top_srcdir)/libusb
 LDADD = ../libusb/libusb-1.0.la
 LDADD = ../libusb/libusb-1.0.la
-noinst_PROGRAMS = listdevs hotplugtest testlibusb1
+
+noinst_PROGRAMS = listdevs xusb fxload hotplugtest
 
 
 if HAVE_SIGACTION
 if HAVE_SIGACTION
 noinst_PROGRAMS += dpfp
 noinst_PROGRAMS += dpfp
@@ -13,3 +14,6 @@ endif
 sam3u_benchmark_SOURCES = sam3u_benchmark.c
 sam3u_benchmark_SOURCES = sam3u_benchmark.c
 noinst_PROGRAMS += sam3u_benchmark
 noinst_PROGRAMS += sam3u_benchmark
 endif
 endif
+
+fxload_SOURCES = ezusb.c ezusb.h fxload.c
+fxload_CFLAGS = $(THREAD_CFLAGS) $(AM_CFLAGS)

+ 4 - 5
compat/libusb-1.0/examples/dpfp.c

@@ -1,6 +1,6 @@
 /*
 /*
- * libusb example program to manipulate U.are.U 4000B fingerprint scanner.
- * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ * libusbx example program to manipulate U.are.U 4000B fingerprint scanner.
+ * Copyright © 2007 Daniel Drake <dsd@gentoo.org>
  *
  *
  * Basic image capture program only, does not consider the powerup quirks or
  * Basic image capture program only, does not consider the powerup quirks or
  * the fact that image encryption may be enabled. Not expected to work
  * the fact that image encryption may be enabled. Not expected to work
@@ -27,7 +27,7 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 
 
-#include <libusb.h>
+#include "libusb.h"
 
 
 #define EP_INTR			(1 | LIBUSB_ENDPOINT_IN)
 #define EP_INTR			(1 | LIBUSB_ENDPOINT_IN)
 #define EP_DATA			(2 | LIBUSB_ENDPOINT_IN)
 #define EP_DATA			(2 | LIBUSB_ENDPOINT_IN)
@@ -164,7 +164,7 @@ static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer)
 
 
 static int set_mode_async(unsigned char data)
 static int set_mode_async(unsigned char data)
 {
 {
-	unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
+	unsigned char *buf = (unsigned char*) malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
 	struct libusb_transfer *transfer;
 	struct libusb_transfer *transfer;
 
 
 	if (!buf)
 	if (!buf)
@@ -504,4 +504,3 @@ out:
 	libusb_exit(NULL);
 	libusb_exit(NULL);
 	return r >= 0 ? r : -r;
 	return r >= 0 ? r : -r;
 }
 }
-

+ 4 - 5
compat/libusb-1.0/examples/dpfp_threaded.c

@@ -1,6 +1,6 @@
 /*
 /*
- * libusb example program to manipulate U.are.U 4000B fingerprint scanner.
- * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ * libusbx example program to manipulate U.are.U 4000B fingerprint scanner.
+ * Copyright © 2007 Daniel Drake <dsd@gentoo.org>
  *
  *
  * Basic image capture program only, does not consider the powerup quirks or
  * Basic image capture program only, does not consider the powerup quirks or
  * the fact that image encryption may be enabled. Not expected to work
  * the fact that image encryption may be enabled. Not expected to work
@@ -28,7 +28,7 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 
 
-#include <libusb.h>
+#include "libusb.h"
 
 
 #define EP_INTR			(1 | LIBUSB_ENDPOINT_IN)
 #define EP_INTR			(1 | LIBUSB_ENDPOINT_IN)
 #define EP_DATA			(2 | LIBUSB_ENDPOINT_IN)
 #define EP_DATA			(2 | LIBUSB_ENDPOINT_IN)
@@ -193,7 +193,7 @@ static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer)
 
 
 static int set_mode_async(unsigned char data)
 static int set_mode_async(unsigned char data)
 {
 {
-	unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
+	unsigned char *buf = (unsigned char*) malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
 	struct libusb_transfer *transfer;
 	struct libusb_transfer *transfer;
 
 
 	if (!buf)
 	if (!buf)
@@ -542,4 +542,3 @@ out:
 	libusb_exit(NULL);
 	libusb_exit(NULL);
 	return r >= 0 ? r : -r;
 	return r >= 0 ? r : -r;
 }
 }
-

+ 60 - 58
compat/libusb-1.0/examples/hotplugtest.c

@@ -1,6 +1,7 @@
+/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
 /*
 /*
  * libusb example program for hotplug API
  * libusb example program for hotplug API
- * Copyright (C) 2012-2013 Nathan Hjelm <hjelmn@mac.ccom>
+ * Copyright © 2012-2013 Nathan Hjelm <hjelmn@mac.ccom>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -19,77 +20,78 @@
 
 
 #include <stdlib.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdio.h>
-#include <sched.h>
-#include <unistd.h>
 
 
-#include <libusb.h>
+#include "libusb.h"
 
 
 int done = 0;
 int done = 0;
 libusb_device_handle *handle;
 libusb_device_handle *handle;
 
 
-static int hotplug_callback (libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data) {
-  struct libusb_device_descriptor desc;
-  int rc;
+static int LIBUSB_CALL hotplug_callback(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data)
+{
+	struct libusb_device_descriptor desc;
+	int rc;
 
 
-  rc = libusb_get_device_descriptor(dev, &desc);
-  if (LIBUSB_SUCCESS != rc) {
-    fprintf (stderr, "Error getting device descriptor\n");
-  }
+	rc = libusb_get_device_descriptor(dev, &desc);
+	if (LIBUSB_SUCCESS != rc) {
+		fprintf (stderr, "Error getting device descriptor\n");
+	}
 
 
-  printf ("Device attach: %04x:%04x\n", desc.idVendor, desc.idProduct);
+	printf ("Device attached: %04x:%04x\n", desc.idVendor, desc.idProduct);
 
 
-  libusb_open (dev, &handle);
+	libusb_open (dev, &handle);
 
 
-  done++;
+	done++;
 
 
-  return 0;
+	return 0;
 }
 }
 
 
-static int hotplug_callback_detach (libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data) {
-  printf ("Device detached\n");
+static int LIBUSB_CALL hotplug_callback_detach(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data)
+{
+	printf ("Device detached\n");
 
 
-  libusb_close (handle);
+	libusb_close (handle);
 
 
-  done++;
-  return 0;
+	done++;
+	return 0;
 }
 }
 
 
-int main (int argc, char *argv[]) {
-  libusb_hotplug_callback_handle hp[2];
-  int product_id, vendor_id, class_id;
-  int rc;
-
-  vendor_id  = (argc > 1) ? strtol (argv[1], NULL, 0) : 0x045a;
-  product_id = (argc > 2) ? strtol (argv[2], NULL, 0) : 0x5005;
-  class_id   = (argc > 3) ? strtol (argv[3], NULL, 0) : LIBUSB_HOTPLUG_MATCH_ANY;
-
-  libusb_init (NULL);
-
-  if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) {
-    printf ("Hotplug not supported by this build of libusb\n");
-    libusb_exit (NULL);
-    return EXIT_FAILURE;
-  }
-
-  rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0, vendor_id,
-                                         product_id, class_id, hotplug_callback, NULL, &hp[0]);
-  if (LIBUSB_SUCCESS != rc) {
-    fprintf (stderr, "Error registering callback 0\n");
-    libusb_exit (NULL);
-    return EXIT_FAILURE;
-  }
-
-  rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, vendor_id,
-                                         product_id,class_id, hotplug_callback_detach, NULL, &hp[1]);
-  if (LIBUSB_SUCCESS != rc) {
-    fprintf (stderr, "Error registering callback 1\n");
-    libusb_exit (NULL);
-    return EXIT_FAILURE;
-  }
-
-  while (done < 2) {
-    libusb_handle_events (NULL);
-  }
-
-  libusb_exit (NULL);
+int main(int argc, char *argv[])
+{
+	libusb_hotplug_callback_handle hp[2];
+	int product_id, vendor_id, class_id;
+	int rc;
+
+	vendor_id  = (argc > 1) ? strtol (argv[1], NULL, 0) : 0x045a;
+	product_id = (argc > 2) ? strtol (argv[2], NULL, 0) : 0x5005;
+	class_id   = (argc > 3) ? strtol (argv[3], NULL, 0) : LIBUSB_HOTPLUG_MATCH_ANY;
+
+	libusb_init (NULL);
+
+	if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) {
+		printf ("Hotplug capabilites are not supported on this platform\n");
+		libusb_exit (NULL);
+		return EXIT_FAILURE;
+	}
+
+	rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0, vendor_id,
+		product_id, class_id, hotplug_callback, NULL, &hp[0]);
+	if (LIBUSB_SUCCESS != rc) {
+		fprintf (stderr, "Error registering callback 0\n");
+		libusb_exit (NULL);
+		return EXIT_FAILURE;
+	}
+
+	rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, vendor_id,
+		product_id,class_id, hotplug_callback_detach, NULL, &hp[1]);
+	if (LIBUSB_SUCCESS != rc) {
+		fprintf (stderr, "Error registering callback 1\n");
+		libusb_exit (NULL);
+		return EXIT_FAILURE;
+	}
+
+	while (done < 2) {
+		libusb_handle_events (NULL);
+	}
+
+	libusb_exit (NULL);
 }
 }

+ 14 - 7
compat/libusb-1.0/examples/listdevs.c

@@ -1,6 +1,6 @@
 /*
 /*
- * libusb example program to list devices on the bus
- * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ * libusbx example program to list devices on the bus
+ * Copyright © 2007 Daniel Drake <dsd@gentoo.org>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -18,14 +18,14 @@
  */
  */
 
 
 #include <stdio.h>
 #include <stdio.h>
-#include <sys/types.h>
 
 
-#include <libusb.h>
+#include "libusb.h"
 
 
 static void print_devs(libusb_device **devs)
 static void print_devs(libusb_device **devs)
 {
 {
 	libusb_device *dev;
 	libusb_device *dev;
-	int i = 0;
+	int i = 0, j = 0;
+	uint8_t path[8]; 
 
 
 	while ((dev = devs[i++]) != NULL) {
 	while ((dev = devs[i++]) != NULL) {
 		struct libusb_device_descriptor desc;
 		struct libusb_device_descriptor desc;
@@ -35,9 +35,17 @@ static void print_devs(libusb_device **devs)
 			return;
 			return;
 		}
 		}
 
 
-		printf("%04x:%04x (bus %d, device %d)\n",
+		printf("%04x:%04x (bus %d, device %d)",
 			desc.idVendor, desc.idProduct,
 			desc.idVendor, desc.idProduct,
 			libusb_get_bus_number(dev), libusb_get_device_address(dev));
 			libusb_get_bus_number(dev), libusb_get_device_address(dev));
+
+		r = libusb_get_port_numbers(dev, path, sizeof(path));
+		if (r > 0) {
+			printf(" path: %d", path[0]);
+			for (j = 1; j < r; j++)
+				printf(".%d", path[j]);
+		}
+		printf("\n");
 	}
 	}
 }
 }
 
 
@@ -61,4 +69,3 @@ int main(void)
 	libusb_exit(NULL);
 	libusb_exit(NULL);
 	return 0;
 	return 0;
 }
 }
-

+ 1 - 1
compat/libusb-1.0/examples/sam3u_benchmark.c

@@ -40,7 +40,7 @@ static struct libusb_device_handle *devh = NULL;
 static unsigned long num_bytes = 0, num_xfer = 0;
 static unsigned long num_bytes = 0, num_xfer = 0;
 static struct timeval tv_start;
 static struct timeval tv_start;
 
 
-static void cb_xfr(struct libusb_transfer *xfr)
+static void LIBUSB_CALL cb_xfr(struct libusb_transfer *xfr)
 {
 {
 	unsigned int i;
 	unsigned int i;
 
 

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

@@ -1,256 +0,0 @@
-/*
- * Test suite program based of libusb-0.1-compat testlibusb
- * Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.ccom>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <libusb.h>
-
-int verbose = 0;
-
-static void print_endpoint_comp(const struct libusb_ss_endpoint_companion_descriptor *ep_comp)
-{
-  printf("      USB 3.0 Endpoint Companion:\n");
-  printf("        bMaxBurst:        %d\n", ep_comp->bMaxBurst);
-  printf("        bmAttributes:     0x%02x\n", ep_comp->bmAttributes);
-  printf("        wBytesPerInterval: %d\n", ep_comp->wBytesPerInterval);
-}
-
-static void print_endpoint(const struct libusb_endpoint_descriptor *endpoint)
-{
-  int i, ret;
-
-  printf("      Endpoint:\n");
-  printf("        bEndpointAddress: %02xh\n", endpoint->bEndpointAddress);
-  printf("        bmAttributes:     %02xh\n", endpoint->bmAttributes);
-  printf("        wMaxPacketSize:   %d\n", endpoint->wMaxPacketSize);
-  printf("        bInterval:        %d\n", endpoint->bInterval);
-  printf("        bRefresh:         %d\n", endpoint->bRefresh);
-  printf("        bSynchAddress:    %d\n", endpoint->bSynchAddress);
-
-  for (i = 0 ; i < endpoint->extra_length ; ) {
-    if (LIBUSB_DT_SS_ENDPOINT_COMPANION == endpoint->extra[i+1]) {
-      struct libusb_ss_endpoint_companion_descriptor *ep_comp;
-
-      ret = libusb_parse_ss_endpoint_comp(endpoint->extra+i, endpoint->extra[0], &ep_comp);
-      if (LIBUSB_SUCCESS != ret) {
-        continue;
-      }
-
-      print_endpoint_comp(ep_comp);
-
-      libusb_free_ss_endpoint_comp(ep_comp);
-    }
-
-    i += endpoint->extra[i];
-  }
-}
-
-static void print_altsetting(const struct libusb_interface_descriptor *interface)
-{
-  int i;
-
-  printf("    Interface:\n");
-  printf("      bInterfaceNumber:   %d\n", interface->bInterfaceNumber);
-  printf("      bAlternateSetting:  %d\n", interface->bAlternateSetting);
-  printf("      bNumEndpoints:      %d\n", interface->bNumEndpoints);
-  printf("      bInterfaceClass:    %d\n", interface->bInterfaceClass);
-  printf("      bInterfaceSubClass: %d\n", interface->bInterfaceSubClass);
-  printf("      bInterfaceProtocol: %d\n", interface->bInterfaceProtocol);
-  printf("      iInterface:         %d\n", interface->iInterface);
-
-  for (i = 0; i < interface->bNumEndpoints; i++)
-    print_endpoint(&interface->endpoint[i]);
-}
-
-static void print_2_0_ext_cap(struct libusb_usb_2_0_device_capability_descriptor *usb_2_0_ext_cap)
-{
-  printf("    USB 2.0 Extension Capabilities:\n");
-  printf("      bDevCapabilityType: %d\n", usb_2_0_ext_cap->bDevCapabilityType);
-  printf("      bmAttributes:       0x%x\n", usb_2_0_ext_cap->bmAttributes);
-}
-
-static void print_ss_usb_cap(struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap)
-{
-  printf("    USB 3.0 Capabilities:\n");
-  printf("      bDevCapabilityType: %d\n", ss_usb_cap->bDevCapabilityType);
-  printf("      bmAttributes:       0x%x\n", ss_usb_cap->bmAttributes);
-  printf("      wSpeedSupported:    0x%x\n", ss_usb_cap->wSpeedSupported);
-  printf("      bFunctionalitySupport: %d\n", ss_usb_cap->bFunctionalitySupport);
-  printf("      bU1devExitLat:      %d\n", ss_usb_cap->bU1DevExitLat);
-  printf("      bU2devExitLat:      %d\n", ss_usb_cap->bU2DevExitLat);
-}
-
-static void print_bos(libusb_device_handle *handle)
-{
-  unsigned char buffer[128];
-  struct libusb_bos_descriptor *bos;
-  int ret;
-
-  ret = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, buffer, 128);
-  if (0 > ret) {
-    return;
-  }
-
-  ret = libusb_parse_bos_descriptor(buffer, 128, &bos);
-  if (0 > ret) {
-    return;
-  }
-
-  printf("  Binary Object Store (BOS):\n");
-  printf("    wTotalLength:       %d\n", bos->wTotalLength);
-  printf("    bNumDeviceCaps:     %d\n", bos->bNumDeviceCaps);
-  if (bos->usb_2_0_ext_cap) {
-    print_2_0_ext_cap(bos->usb_2_0_ext_cap);
-  }
-
-  if (bos->ss_usb_cap) {
-    print_ss_usb_cap(bos->ss_usb_cap);
-  }
-}
-
-static void print_interface(const struct libusb_interface *interface)
-{
-  int i;
-
-  for (i = 0; i < interface->num_altsetting; i++)
-    print_altsetting(&interface->altsetting[i]);
-}
-
-static void print_configuration(struct libusb_config_descriptor *config)
-{
-  int i;
-
-  printf("  Configuration:\n");
-  printf("    wTotalLength:         %d\n", config->wTotalLength);
-  printf("    bNumInterfaces:       %d\n", config->bNumInterfaces);
-  printf("    bConfigurationValue:  %d\n", config->bConfigurationValue);
-  printf("    iConfiguration:       %d\n", config->iConfiguration);
-  printf("    bmAttributes:         %02xh\n", config->bmAttributes);
-  printf("    MaxPower:             %d\n", config->MaxPower);
-
-  for (i = 0; i < config->bNumInterfaces; i++)
-    print_interface(&config->interface[i]);
-}
-
-static int print_device(libusb_device *dev, int level)
-{
-  struct libusb_device_descriptor desc;
-  libusb_device_handle *handle = NULL;
-  char description[256];
-  char string[256];
-  int ret, i;
-
-  ret = libusb_get_device_descriptor(dev, &desc);
-  if (ret < 0) {
-    fprintf(stderr, "failed to get device descriptor");
-    return -1;
-  }
-
-  ret = libusb_open(dev, &handle);
-  if (LIBUSB_SUCCESS == ret) {
-    if (desc.iManufacturer) {
-      ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string));
-      if (ret > 0)
-        snprintf(description, sizeof(description), "%s - ", string);
-      else
-        snprintf(description, sizeof(description), "%04X - ",
-                 desc.idVendor);
-    } else
-      snprintf(description, sizeof(description), "%04X - ",
-               desc.idVendor);
-
-    if (desc.iProduct) {
-      ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string));
-      if (ret > 0)
-        snprintf(description + strlen(description), sizeof(description) -
-                 strlen(description), "%s", string);
-      else
-        snprintf(description + strlen(description), sizeof(description) -
-                 strlen(description), "%04X", desc.idProduct);
-    } else
-      snprintf(description + strlen(description), sizeof(description) -
-               strlen(description), "%04X", desc.idProduct);
-  } else {
-    snprintf(description, sizeof(description), "%04X - %04X",
-             desc.idVendor, desc.idProduct);
-  }
-
-  printf("%.*sDev (bus %d, device %d): %s\n", level * 2, "                    ",
-         libusb_get_bus_number(dev), libusb_get_device_address(dev), description);
-
-  if (handle && verbose) {
-    if (desc.iSerialNumber) {
-      ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string));
-      if (ret > 0)
-        printf("%.*s  - Serial Number: %s\n", level * 2,
-               "                    ", string);
-    }
-  }
-
-  if (verbose) {
-    for (i = 0; i < desc.bNumConfigurations; i++) {
-      struct libusb_config_descriptor *config;
-      ret = libusb_get_config_descriptor(dev, i, &config);
-      if (LIBUSB_SUCCESS != ret) {
-        printf("  Couldn't retrieve descriptors\n");
-        continue;
-      }
-
-      print_configuration(config);
-
-      libusb_free_config_descriptor(config);
-    }
-
-    if (handle && desc.bcdUSB >= 0x0201) {
-      print_bos(handle);
-    }
-  }
-
-  if (handle)
-    libusb_close(handle);
-
-  return 0;
-}
-
-int main(int argc, char *argv[])
-{
-  libusb_device **devs;
-  ssize_t cnt;
-  int r, i;
-
-  if (argc > 1 && !strcmp(argv[1], "-v"))
-    verbose = 1;
-
-  r = libusb_init(NULL);
-  if (r < 0)
-    return r;
-
-  cnt = libusb_get_device_list(NULL, &devs);
-  if (cnt < 0)
-    return (int) cnt;
-
-  for (i = 0 ; devs[i] ; ++i) {
-    print_device(devs[i], 0);
-  }
-
-  libusb_free_device_list(devs, 1);
-
-  libusb_exit(NULL);
-  return 0;
-}

+ 2 - 3
compat/libusb-1.0/libusb-1.0.pc.in

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

+ 33 - 13
compat/libusb-1.0/libusb/Makefile.am

@@ -1,32 +1,46 @@
+all: libusb-1.0.la libusb-1.0.dll
+
+AUTOMAKE_OPTIONS = subdir-objects
+
 lib_LTLIBRARIES = libusb-1.0.la
 lib_LTLIBRARIES = libusb-1.0.la
 
 
+POSIX_POLL_SRC = os/poll_posix.c
 LINUX_USBFS_SRC = os/linux_usbfs.c
 LINUX_USBFS_SRC = os/linux_usbfs.c
 DARWIN_USB_SRC = os/darwin_usb.c
 DARWIN_USB_SRC = os/darwin_usb.c
 OPENBSD_USB_SRC = os/openbsd_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
+NETBSD_USB_SRC = os/netbsd_usb.c
+WINDOWS_USB_SRC = os/poll_windows.c os/windows_usb.c libusb-1.0.rc libusb-1.0.def
+WINCE_USB_SRC = os/wince_usb.c os/wince_usb.h
 
 
 EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(OPENBSD_USB_SRC) \
 EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(OPENBSD_USB_SRC) \
-	$(WINDOWS_USB_SRC) os/threads_posix.c os/threads_windows.c \
+	$(NETBSD_USB_SRC) $(WINDOWS_USB_SRC) $(WINCE_USB_SRC) \
+	$(POSIX_POLL_SRC) \
+	os/threads_posix.c os/threads_windows.c \
 	os/linux_udev.c os/linux_netlink.c
 	os/linux_udev.c os/linux_netlink.c
 
 
 if OS_LINUX
 if OS_LINUX
 
 
 if USE_UDEV
 if USE_UDEV
-OS_SRC = $(LINUX_USBFS_SRC) os/linux_udev.c
+OS_SRC = $(LINUX_USBFS_SRC) $(POSIX_POLL_SRC) \
+	os/linux_udev.c
 else
 else
-OS_SRC = $(LINUX_USBFS_SRC) os/linux_netlink.c
+OS_SRC = $(LINUX_USBFS_SRC) $(POSIX_POLL_SRC) \
+	os/linux_netlink.c
 endif
 endif
 
 
 endif
 endif
 
 
 if OS_DARWIN
 if OS_DARWIN
-OS_SRC = $(DARWIN_USB_SRC)
+OS_SRC = $(DARWIN_USB_SRC) $(POSIX_POLL_SRC)
 AM_CFLAGS_EXT = -no-cpp-precomp
 AM_CFLAGS_EXT = -no-cpp-precomp
 endif
 endif
 
 
 if OS_OPENBSD
 if OS_OPENBSD
-OS_SRC = $(OPENBSD_USB_SRC)
+OS_SRC = $(OPENBSD_USB_SRC) $(POSIX_POLL_SRC)
+endif
+
+if OS_NETBSD
+OS_SRC = $(NETBSD_USB_SRC) $(POSIX_POLL_SRC)
 endif
 endif
 
 
 if OS_WINDOWS
 if OS_WINDOWS
@@ -35,7 +49,13 @@ OS_SRC = $(WINDOWS_USB_SRC)
 .rc.lo:
 .rc.lo:
 	$(AM_V_GEN)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@
 	$(AM_V_GEN)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@
 
 
-libusb-1.0.rc: version.h
+libusb-1.0.rc: version.h version_nano.h
+endif
+
+libusb-1.0.dll: libusb-1.0.def
+if CREATE_IMPORT_LIB
+# Rebuild the import lib from the .def so that MS and MinGW DLLs can be interchanged
+	$(AM_V_GEN)$(DLLTOOL) $(DLLTOOLFLAGS) --kill-at --input-def $(srcdir)/libusb-1.0.def --dllname $@ --output-lib .libs/$@.a
 endif
 endif
 
 
 if THREADS_POSIX
 if THREADS_POSIX
@@ -44,12 +64,12 @@ else
 THREADS_SRC = os/threads_windows.h os/threads_windows.c
 THREADS_SRC = os/threads_windows.h os/threads_windows.c
 endif
 endif
 
 
-libusb_1_0_la_CFLAGS = $(AM_CFLAGS) \
-	-DLIBUSB_DESCRIBE=\"`git --git-dir "$(top_srcdir)/.git" describe --tags 2>/dev/null`\"
+libusb_1_0_la_CFLAGS = $(AM_CFLAGS)
 libusb_1_0_la_LDFLAGS = $(LTLDFLAGS)
 libusb_1_0_la_LDFLAGS = $(LTLDFLAGS)
-libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c sync.c $(OS_SRC) \
-	hotplug.h hotplug.c os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h \
-	$(THREADS_SRC) os/poll_posix.h os/poll_windows.h
+libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c strerror.c sync.c \
+	os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h os/windows_common.h \
+	hotplug.h hotplug.c $(THREADS_SRC) $(OS_SRC) \
+	os/poll_posix.h os/poll_windows.h
 
 
 hdrdir = $(includedir)/libusb-1.0
 hdrdir = $(includedir)/libusb-1.0
 hdr_HEADERS = libusb.h
 hdr_HEADERS = libusb.h

File diff suppressed because it is too large
+ 346 - 203
compat/libusb-1.0/libusb/core.c


+ 584 - 257
compat/libusb-1.0/libusb/descriptor.c

@@ -1,8 +1,8 @@
+/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
 /*
 /*
- * USB descriptor handling functions for libusb
- * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
- * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
- * Copyright (c) 2012-2013 Nathan Hjelm <hjelmn@cs.unm.edu>
+ * USB descriptor handling functions for libusbx
+ * Copyright © 2007 Daniel Drake <dsd@gentoo.org>
+ * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -23,8 +23,6 @@
 #include <stdint.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
-#include <stdio.h>
-#include <assert.h>
 
 
 #include "libusbi.h"
 #include "libusbi.h"
 
 
@@ -68,10 +66,8 @@ int usbi_parse_descriptor(const unsigned char *source, const char *descriptor,
 				sp += 2;
 				sp += 2;
 				dp += 2;
 				dp += 2;
 				break;
 				break;
-			/* 32-bit word, convert from little endian to CPU */
-			case 'd':
-			/* Align to word boundary */
-				dp += ((unsigned long)dp & 1);
+			case 'd':	/* 32-bit word, convert from little endian to CPU */
+				dp += ((uintptr_t)dp & 1);	/* Align to word boundary */
 
 
 				if (host_endian) {
 				if (host_endian) {
 					memcpy(dp, sp, 4);
 					memcpy(dp, sp, 4);
@@ -83,6 +79,11 @@ int usbi_parse_descriptor(const unsigned char *source, const char *descriptor,
 				sp += 4;
 				sp += 4;
 				dp += 4;
 				dp += 4;
 				break;
 				break;
+			case 'u':	/* 16 byte UUID */
+				memcpy(dp, sp, 16);
+				sp += 16;
+				dp += 16;
+				break;
 		}
 		}
 	}
 	}
 
 
@@ -105,25 +106,31 @@ static int parse_endpoint(struct libusb_context *ctx,
 	int parsed = 0;
 	int parsed = 0;
 	int len;
 	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 (size < DESC_HEADER_LENGTH) {
+		usbi_err(ctx, "short endpoint descriptor read %d/%d",
+			 size, DESC_HEADER_LENGTH);
+		return LIBUSB_ERROR_IO;
 	}
 	}
 
 
+	usbi_parse_descriptor(buffer, "bb", &header, 0);
 	if (header.bDescriptorType != LIBUSB_DT_ENDPOINT) {
 	if (header.bDescriptorType != LIBUSB_DT_ENDPOINT) {
 		usbi_err(ctx, "unexpected descriptor %x (expected %x)",
 		usbi_err(ctx, "unexpected descriptor %x (expected %x)",
 			header.bDescriptorType, LIBUSB_DT_ENDPOINT);
 			header.bDescriptorType, LIBUSB_DT_ENDPOINT);
 		return parsed;
 		return parsed;
 	}
 	}
-
+	if (header.bLength > size) {
+		usbi_warn(ctx, "short endpoint descriptor read %d/%d",
+			  size, header.bLength);
+		return parsed;
+	}
 	if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH)
 	if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH)
 		usbi_parse_descriptor(buffer, "bbbbwbbb", endpoint, host_endian);
 		usbi_parse_descriptor(buffer, "bbbbwbbb", endpoint, host_endian);
 	else if (header.bLength >= ENDPOINT_DESC_LENGTH)
 	else if (header.bLength >= ENDPOINT_DESC_LENGTH)
 		usbi_parse_descriptor(buffer, "bbbbwb", endpoint, host_endian);
 		usbi_parse_descriptor(buffer, "bbbbwb", endpoint, host_endian);
+	else {
+		usbi_err(ctx, "invalid endpoint bLength (%d)", header.bLength);
+		return LIBUSB_ERROR_IO;
+	}
 
 
 	buffer += header.bLength;
 	buffer += header.bLength;
 	size -= header.bLength;
 	size -= header.bLength;
@@ -134,17 +141,21 @@ static int parse_endpoint(struct libusb_context *ctx,
 	begin = buffer;
 	begin = buffer;
 	while (size >= DESC_HEADER_LENGTH) {
 	while (size >= DESC_HEADER_LENGTH) {
 		usbi_parse_descriptor(buffer, "bb", &header, 0);
 		usbi_parse_descriptor(buffer, "bb", &header, 0);
-
-		if (header.bLength < 2) {
-			usbi_err(ctx, "invalid descriptor length %d", header.bLength);
-			return -1;
+		if (header.bLength < DESC_HEADER_LENGTH) {
+			usbi_err(ctx, "invalid extra ep desc len (%d)",
+				 header.bLength);
+			return LIBUSB_ERROR_IO;
+		} else if (header.bLength > size) {
+			usbi_warn(ctx, "short extra ep desc read %d/%d",
+				  size, header.bLength);
+			return parsed;
 		}
 		}
 
 
 		/* If we find another "proper" descriptor then we're done  */
 		/* If we find another "proper" descriptor then we're done  */
 		if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
 		if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
-		    (header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
-		    (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
-		    (header.bDescriptorType == LIBUSB_DT_DEVICE))
+				(header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
+				(header.bDescriptorType == LIBUSB_DT_CONFIG) ||
+				(header.bDescriptorType == LIBUSB_DT_DEVICE))
 			break;
 			break;
 
 
 		usbi_dbg("skipping descriptor %x", header.bDescriptorType);
 		usbi_dbg("skipping descriptor %x", header.bDescriptorType);
@@ -208,6 +219,7 @@ static int parse_interface(libusb_context *ctx,
 	int len;
 	int len;
 	int r;
 	int r;
 	int parsed = 0;
 	int parsed = 0;
+	int interface_number = -1;
 	size_t tmp;
 	size_t tmp;
 	struct usb_descriptor_header header;
 	struct usb_descriptor_header header;
 	struct libusb_interface_descriptor *ifp;
 	struct libusb_interface_descriptor *ifp;
@@ -218,7 +230,7 @@ static int parse_interface(libusb_context *ctx,
 	while (size >= INTERFACE_DESC_LENGTH) {
 	while (size >= INTERFACE_DESC_LENGTH) {
 		struct libusb_interface_descriptor *altsetting =
 		struct libusb_interface_descriptor *altsetting =
 			(struct libusb_interface_descriptor *) usb_interface->altsetting;
 			(struct libusb_interface_descriptor *) usb_interface->altsetting;
-		altsetting = realloc(altsetting,
+		altsetting = usbi_reallocf(altsetting,
 			sizeof(struct libusb_interface_descriptor) *
 			sizeof(struct libusb_interface_descriptor) *
 			(usb_interface->num_altsetting + 1));
 			(usb_interface->num_altsetting + 1));
 		if (!altsetting) {
 		if (!altsetting) {
@@ -228,12 +240,37 @@ static int parse_interface(libusb_context *ctx,
 		usb_interface->altsetting = altsetting;
 		usb_interface->altsetting = altsetting;
 
 
 		ifp = altsetting + usb_interface->num_altsetting;
 		ifp = altsetting + usb_interface->num_altsetting;
-		usb_interface->num_altsetting++;
 		usbi_parse_descriptor(buffer, "bbbbbbbbb", ifp, 0);
 		usbi_parse_descriptor(buffer, "bbbbbbbbb", ifp, 0);
+		if (ifp->bDescriptorType != LIBUSB_DT_INTERFACE) {
+			usbi_err(ctx, "unexpected descriptor %x (expected %x)",
+				 ifp->bDescriptorType, LIBUSB_DT_INTERFACE);
+			return parsed;
+		}
+		if (ifp->bLength < INTERFACE_DESC_LENGTH) {
+			usbi_err(ctx, "invalid interface bLength (%d)",
+				 ifp->bLength);
+			r = LIBUSB_ERROR_IO;
+			goto err;
+		}
+		if (ifp->bLength > size) {
+			usbi_warn(ctx, "short intf descriptor read %d/%d",
+				 size, ifp->bLength);
+			return parsed;
+		}
+		if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
+			usbi_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoints);
+			r = LIBUSB_ERROR_IO;
+			goto err;
+		}
+
+		usb_interface->num_altsetting++;
 		ifp->extra = NULL;
 		ifp->extra = NULL;
 		ifp->extra_length = 0;
 		ifp->extra_length = 0;
 		ifp->endpoint = NULL;
 		ifp->endpoint = NULL;
 
 
+		if (interface_number == -1)
+			interface_number = ifp->bInterfaceNumber;
+
 		/* Skip over the interface */
 		/* Skip over the interface */
 		buffer += ifp->bLength;
 		buffer += ifp->bLength;
 		parsed += ifp->bLength;
 		parsed += ifp->bLength;
@@ -244,20 +281,24 @@ static int parse_interface(libusb_context *ctx,
 		/* Skip over any interface, class or vendor descriptors */
 		/* Skip over any interface, class or vendor descriptors */
 		while (size >= DESC_HEADER_LENGTH) {
 		while (size >= DESC_HEADER_LENGTH) {
 			usbi_parse_descriptor(buffer, "bb", &header, 0);
 			usbi_parse_descriptor(buffer, "bb", &header, 0);
-			if (header.bLength < 2) {
-				usbi_err(ctx, "invalid descriptor of length %d",
-					header.bLength);
+			if (header.bLength < DESC_HEADER_LENGTH) {
+				usbi_err(ctx,
+					 "invalid extra intf desc len (%d)",
+					 header.bLength);
 				r = LIBUSB_ERROR_IO;
 				r = LIBUSB_ERROR_IO;
 				goto err;
 				goto err;
+			} else if (header.bLength > size) {
+				usbi_warn(ctx,
+					  "short extra intf desc read %d/%d",
+					  size, header.bLength);
+				return parsed;
 			}
 			}
 
 
 			/* If we find another "proper" descriptor then we're done */
 			/* If we find another "proper" descriptor then we're done */
 			if ((header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
 			if ((header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
-			    (header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
-			    (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
-			    (header.bDescriptorType == LIBUSB_DT_DEVICE) ||
-			    (header.bDescriptorType ==
-			     LIBUSB_DT_SS_ENDPOINT_COMPANION))
+					(header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
+					(header.bDescriptorType == LIBUSB_DT_CONFIG) ||
+					(header.bDescriptorType == LIBUSB_DT_DEVICE))
 				break;
 				break;
 
 
 			buffer += header.bLength;
 			buffer += header.bLength;
@@ -278,21 +319,6 @@ static int parse_interface(libusb_context *ctx,
 			ifp->extra_length = 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) {
 		if (ifp->bNumEndpoints > 0) {
 			struct libusb_endpoint_descriptor *endpoint;
 			struct libusb_endpoint_descriptor *endpoint;
 			tmp = ifp->bNumEndpoints * sizeof(struct libusb_endpoint_descriptor);
 			tmp = ifp->bNumEndpoints * sizeof(struct libusb_endpoint_descriptor);
@@ -305,18 +331,14 @@ static int parse_interface(libusb_context *ctx,
 
 
 			memset(endpoint, 0, tmp);
 			memset(endpoint, 0, tmp);
 			for (i = 0; i < ifp->bNumEndpoints; i++) {
 			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,
 				r = parse_endpoint(ctx, endpoint + i, buffer, size,
 					host_endian);
 					host_endian);
 				if (r < 0)
 				if (r < 0)
 					goto err;
 					goto err;
+				if (r == 0) {
+					ifp->bNumEndpoints = (uint8_t)i;
+					break;;
+				}
 
 
 				buffer += r;
 				buffer += r;
 				parsed += r;
 				parsed += r;
@@ -328,7 +350,7 @@ static int parse_interface(libusb_context *ctx,
 		ifp = (struct libusb_interface_descriptor *) buffer;
 		ifp = (struct libusb_interface_descriptor *) buffer;
 		if (size < LIBUSB_DT_INTERFACE_SIZE ||
 		if (size < LIBUSB_DT_INTERFACE_SIZE ||
 				ifp->bDescriptorType != LIBUSB_DT_INTERFACE ||
 				ifp->bDescriptorType != LIBUSB_DT_INTERFACE ||
-				!ifp->bAlternateSetting)
+				ifp->bInterfaceNumber != interface_number)
 			return parsed;
 			return parsed;
 	}
 	}
 
 
@@ -353,18 +375,35 @@ static void clear_configuration(struct libusb_config_descriptor *config)
 
 
 static int parse_configuration(struct libusb_context *ctx,
 static int parse_configuration(struct libusb_context *ctx,
 	struct libusb_config_descriptor *config, unsigned char *buffer,
 	struct libusb_config_descriptor *config, unsigned char *buffer,
-	int host_endian)
+	int size, int host_endian)
 {
 {
 	int i;
 	int i;
 	int r;
 	int r;
-	int size;
 	size_t tmp;
 	size_t tmp;
 	struct usb_descriptor_header header;
 	struct usb_descriptor_header header;
 	struct libusb_interface *usb_interface;
 	struct libusb_interface *usb_interface;
 
 
-	usbi_parse_descriptor(buffer, "bbwbbbbb", config, host_endian);
-	size = config->wTotalLength;
+	if (size < LIBUSB_DT_CONFIG_SIZE) {
+		usbi_err(ctx, "short config descriptor read %d/%d",
+			 size, LIBUSB_DT_CONFIG_SIZE);
+		return LIBUSB_ERROR_IO;
+	}
 
 
+	usbi_parse_descriptor(buffer, "bbwbbbbb", config, host_endian);
+	if (config->bDescriptorType != LIBUSB_DT_CONFIG) {
+		usbi_err(ctx, "unexpected descriptor %x (expected %x)",
+			 config->bDescriptorType, LIBUSB_DT_CONFIG);
+		return LIBUSB_ERROR_IO;
+	}
+	if (config->bLength < LIBUSB_DT_CONFIG_SIZE) {
+		usbi_err(ctx, "invalid config bLength (%d)", config->bLength);
+		return LIBUSB_ERROR_IO;
+	}
+	if (config->bLength > size) {
+		usbi_err(ctx, "short config descriptor read %d/%d",
+			 size, config->bLength);
+		return LIBUSB_ERROR_IO;
+	}
 	if (config->bNumInterfaces > USB_MAXINTERFACES) {
 	if (config->bNumInterfaces > USB_MAXINTERFACES) {
 		usbi_err(ctx, "too many interfaces (%d)", config->bNumInterfaces);
 		usbi_err(ctx, "too many interfaces (%d)", config->bNumInterfaces);
 		return LIBUSB_ERROR_IO;
 		return LIBUSB_ERROR_IO;
@@ -393,21 +432,25 @@ static int parse_configuration(struct libusb_context *ctx,
 		while (size >= DESC_HEADER_LENGTH) {
 		while (size >= DESC_HEADER_LENGTH) {
 			usbi_parse_descriptor(buffer, "bb", &header, 0);
 			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);
+			if (header.bLength < DESC_HEADER_LENGTH) {
+				usbi_err(ctx,
+					 "invalid extra config desc len (%d)",
+					 header.bLength);
 				r = LIBUSB_ERROR_IO;
 				r = LIBUSB_ERROR_IO;
 				goto err;
 				goto err;
+			} else if (header.bLength > size) {
+				usbi_warn(ctx,
+					  "short extra config desc read %d/%d",
+					  size, header.bLength);
+				config->bNumInterfaces = (uint8_t)i;
+				return size;
 			}
 			}
 
 
 			/* If we find another "proper" descriptor then we're done */
 			/* If we find another "proper" descriptor then we're done */
 			if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
 			if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) ||
-			    (header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
-			    (header.bDescriptorType == LIBUSB_DT_CONFIG) ||
-			    (header.bDescriptorType == LIBUSB_DT_DEVICE) ||
-			    (header.bDescriptorType ==
-			     LIBUSB_DT_SS_ENDPOINT_COMPANION))
+					(header.bDescriptorType == LIBUSB_DT_INTERFACE) ||
+					(header.bDescriptorType == LIBUSB_DT_CONFIG) ||
+					(header.bDescriptorType == LIBUSB_DT_DEVICE))
 				break;
 				break;
 
 
 			usbi_dbg("skipping descriptor 0x%x\n", header.bDescriptorType);
 			usbi_dbg("skipping descriptor 0x%x\n", header.bDescriptorType);
@@ -435,6 +478,10 @@ static int parse_configuration(struct libusb_context *ctx,
 		r = parse_interface(ctx, usb_interface + i, buffer, size, host_endian);
 		r = parse_interface(ctx, usb_interface + i, buffer, size, host_endian);
 		if (r < 0)
 		if (r < 0)
 			goto err;
 			goto err;
+		if (r == 0) {
+			config->bNumInterfaces = (uint8_t)i;
+			break;
+		}
 
 
 		buffer += r;
 		buffer += r;
 		size -= r;
 		size -= r;
@@ -447,9 +494,32 @@ err:
 	return r;
 	return r;
 }
 }
 
 
+static int raw_desc_to_config(struct libusb_context *ctx,
+	unsigned char *buf, int size, int host_endian,
+	struct libusb_config_descriptor **config)
+{
+	struct libusb_config_descriptor *_config = malloc(sizeof(*_config));
+	int r;
+	
+	if (!_config)
+		return LIBUSB_ERROR_NO_MEM;
+
+	r = parse_configuration(ctx, _config, buf, size, host_endian);
+	if (r < 0) {
+		usbi_err(ctx, "parse_configuration failed with error %d", r);
+		free(_config);
+		return r;
+	} else if (r > 0) {
+		usbi_warn(ctx, "still %d bytes of descriptor data left", r);
+	}
+	
+	*config = _config;
+	return LIBUSB_SUCCESS;
+}
+
 int usbi_device_cache_descriptor(libusb_device *dev)
 int usbi_device_cache_descriptor(libusb_device *dev)
 {
 {
-	int r, host_endian;
+	int r, host_endian = 0;
 
 
 	r = usbi_backend->get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor,
 	r = usbi_backend->get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor,
 						&host_endian);
 						&host_endian);
@@ -471,6 +541,9 @@ int usbi_device_cache_descriptor(libusb_device *dev)
  *
  *
  * This is a non-blocking function; the device descriptor is cached in memory.
  * This is a non-blocking function; the device descriptor is cached in memory.
  *
  *
+ * Note since libusbx-1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102, this
+ * function always succeeds.
+ *
  * \param dev the device
  * \param dev the device
  * \param desc output location for the descriptor data
  * \param desc output location for the descriptor data
  * \returns 0 on success or a LIBUSB_ERROR code on failure
  * \returns 0 on success or a LIBUSB_ERROR code on failure
@@ -501,49 +574,33 @@ int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev,
 int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev,
 int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev,
 	struct libusb_config_descriptor **config)
 	struct libusb_config_descriptor **config)
 {
 {
-	struct libusb_config_descriptor *_config = malloc(sizeof(*_config));
-	unsigned char tmp[8];
+	struct libusb_config_descriptor _config;
+	unsigned char tmp[LIBUSB_DT_CONFIG_SIZE];
 	unsigned char *buf = NULL;
 	unsigned char *buf = NULL;
 	int host_endian = 0;
 	int host_endian = 0;
 	int r;
 	int r;
 
 
-	usbi_dbg("");
-	if (!_config)
-		return LIBUSB_ERROR_NO_MEM;
-
-	r = usbi_backend->get_active_config_descriptor(dev, tmp, sizeof(tmp),
-		&host_endian);
+	r = usbi_backend->get_active_config_descriptor(dev, tmp,
+		LIBUSB_DT_CONFIG_SIZE, &host_endian);
 	if (r < 0)
 	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;
+		return r;
+	if (r < LIBUSB_DT_CONFIG_SIZE) {
+		usbi_err(dev->ctx, "short config descriptor read %d/%d",
+			 r, LIBUSB_DT_CONFIG_SIZE);
+		return LIBUSB_ERROR_IO;
 	}
 	}
 
 
-	r = usbi_backend->get_active_config_descriptor(dev, buf,
-		_config->wTotalLength, &host_endian);
-	if (r < 0)
-		goto err;
+	usbi_parse_descriptor(tmp, "bbw", &_config, host_endian);
+	buf = malloc(_config.wTotalLength);
+	if (!buf)
+		return LIBUSB_ERROR_NO_MEM;
 
 
-	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");
-	}
+	r = usbi_backend->get_active_config_descriptor(dev, buf,
+		_config.wTotalLength, &host_endian);
+	if (r >= 0)
+		r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config);
 
 
 	free(buf);
 	free(buf);
-	*config = _config;
-	return 0;
-
-err:
-	free(_config);
-	if (buf)
-		free(buf);
 	return r;
 	return r;
 }
 }
 
 
@@ -566,8 +623,8 @@ err:
 int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
 int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
 	uint8_t config_index, struct libusb_config_descriptor **config)
 	uint8_t config_index, struct libusb_config_descriptor **config)
 {
 {
-	struct libusb_config_descriptor *_config;
-	unsigned char tmp[8];
+	struct libusb_config_descriptor _config;
+	unsigned char tmp[LIBUSB_DT_CONFIG_SIZE];
 	unsigned char *buf = NULL;
 	unsigned char *buf = NULL;
 	int host_endian = 0;
 	int host_endian = 0;
 	int r;
 	int r;
@@ -576,51 +633,34 @@ int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev,
 	if (config_index >= dev->num_configurations)
 	if (config_index >= dev->num_configurations)
 		return LIBUSB_ERROR_NOT_FOUND;
 		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,
 	r = usbi_backend->get_config_descriptor(dev, config_index, tmp,
-		sizeof(tmp), &host_endian);
+		LIBUSB_DT_CONFIG_SIZE, &host_endian);
 	if (r < 0)
 	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;
+		return r;
+	if (r < LIBUSB_DT_CONFIG_SIZE) {
+		usbi_err(dev->ctx, "short config descriptor read %d/%d",
+			 r, LIBUSB_DT_CONFIG_SIZE);
+		return LIBUSB_ERROR_IO;
 	}
 	}
 
 
-	host_endian = 0;
-	r = usbi_backend->get_config_descriptor(dev, config_index, buf,
-		_config->wTotalLength, &host_endian);
-	if (r < 0)
-		goto err;
+	usbi_parse_descriptor(tmp, "bbw", &_config, host_endian);
+	buf = malloc(_config.wTotalLength);
+	if (!buf)
+		return LIBUSB_ERROR_NO_MEM;
 
 
-	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");
-	}
+	r = usbi_backend->get_config_descriptor(dev, config_index, buf,
+		_config.wTotalLength, &host_endian);
+	if (r >= 0)
+		r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config);
 
 
 	free(buf);
 	free(buf);
-	*config = _config;
-	return 0;
-
-err:
-	free(_config);
-	if (buf)
-		free(buf);
 	return r;
 	return r;
 }
 }
 
 
 /* iterate through all configurations, returning the index of the configuration
 /* iterate through all configurations, returning the index of the configuration
  * matching a specific bConfigurationValue in the idx output parameter, or -1
  * matching a specific bConfigurationValue in the idx output parameter, or -1
  * if the config was not found.
  * if the config was not found.
- * returns 0 or a LIBUSB_ERROR code
+ * returns 0 on success or a LIBUSB_ERROR code
  */
  */
 int usbi_get_config_index_by_value(struct libusb_device *dev,
 int usbi_get_config_index_by_value(struct libusb_device *dev,
 	uint8_t bConfigurationValue, int *idx)
 	uint8_t bConfigurationValue, int *idx)
@@ -633,8 +673,10 @@ int usbi_get_config_index_by_value(struct libusb_device *dev,
 		int host_endian;
 		int host_endian;
 		int r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp),
 		int r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp),
 			&host_endian);
 			&host_endian);
-		if (r < 0)
+		if (r < 0) {
+			*idx = -1;
 			return r;
 			return r;
+		}
 		if (tmp[5] == bConfigurationValue) {
 		if (tmp[5] == bConfigurationValue) {
 			*idx = i;
 			*idx = i;
 			return 0;
 			return 0;
@@ -665,8 +707,18 @@ int usbi_get_config_index_by_value(struct libusb_device *dev,
 int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev,
 int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev,
 	uint8_t bConfigurationValue, struct libusb_config_descriptor **config)
 	uint8_t bConfigurationValue, struct libusb_config_descriptor **config)
 {
 {
-	int idx;
-	int r = usbi_get_config_index_by_value(dev, bConfigurationValue, &idx);
+	int r, idx, host_endian;
+	unsigned char *buf = NULL;
+
+	if (usbi_backend->get_config_descriptor_by_value) {
+		r = usbi_backend->get_config_descriptor_by_value(dev,
+			bConfigurationValue, &buf, &host_endian);
+		if (r < 0)
+			return r;
+		return raw_desc_to_config(dev->ctx, buf, r, host_endian, config);
+	}
+
+	r = usbi_get_config_index_by_value(dev, bConfigurationValue, &idx);
 	if (r < 0)
 	if (r < 0)
 		return r;
 		return r;
 	else if (idx == -1)
 	else if (idx == -1)
@@ -693,6 +745,394 @@ void API_EXPORTED libusb_free_config_descriptor(
 	free(config);
 	free(config);
 }
 }
 
 
+/** \ingroup desc
+ * Get an endpoints superspeed endpoint companion descriptor (if any)
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param endpoint endpoint descriptor from which to get the superspeed
+ * endpoint companion descriptor
+ * \param ep_comp output location for the superspeed endpoint companion
+ * descriptor. Only valid if 0 was returned. Must be freed with
+ * libusb_free_ss_endpoint_companion_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
+ */
+int API_EXPORTED libusb_get_ss_endpoint_companion_descriptor(
+	struct libusb_context *ctx,
+	const struct libusb_endpoint_descriptor *endpoint,
+	struct libusb_ss_endpoint_companion_descriptor **ep_comp)
+{
+	struct usb_descriptor_header header;
+	int size = endpoint->extra_length;
+	const unsigned char *buffer = endpoint->extra;
+
+	*ep_comp = NULL;
+
+	while (size >= DESC_HEADER_LENGTH) {
+		usbi_parse_descriptor(buffer, "bb", &header, 0);
+		if (header.bLength < 2 || header.bLength > size) {
+			usbi_err(ctx, "invalid descriptor length %d",
+				 header.bLength);
+			return LIBUSB_ERROR_IO;
+		}
+		if (header.bDescriptorType != LIBUSB_DT_SS_ENDPOINT_COMPANION) {
+			buffer += header.bLength;
+			size -= header.bLength;
+			continue;
+		}
+		if (header.bLength < LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE) {
+			usbi_err(ctx, "invalid ss-ep-comp-desc length %d",
+				 header.bLength);
+			return LIBUSB_ERROR_IO;
+		}
+		*ep_comp = malloc(sizeof(**ep_comp));
+		if (*ep_comp == NULL)
+			return LIBUSB_ERROR_NO_MEM;
+		usbi_parse_descriptor(buffer, "bbbbw", *ep_comp, 0);
+		return LIBUSB_SUCCESS;
+	}
+	return LIBUSB_ERROR_NOT_FOUND;
+}
+
+/** \ingroup desc
+ * Free a superspeed endpoint companion descriptor obtained from
+ * libusb_get_ss_endpoint_companion_descriptor().
+ * It is safe to call this function with a NULL ep_comp parameter, in which
+ * case the function simply returns.
+ *
+ * \param ep_comp the superspeed endpoint companion descriptor to free
+ */
+void API_EXPORTED libusb_free_ss_endpoint_companion_descriptor(
+	struct libusb_ss_endpoint_companion_descriptor *ep_comp)
+{
+	free(ep_comp);
+}
+
+static int parse_bos(struct libusb_context *ctx,
+	struct libusb_bos_descriptor **bos,
+	unsigned char *buffer, int size, int host_endian)
+{
+	struct libusb_bos_descriptor bos_header, *_bos;
+	struct libusb_bos_dev_capability_descriptor dev_cap;
+	int i;
+
+	if (size < LIBUSB_DT_BOS_SIZE) {
+		usbi_err(ctx, "short bos descriptor read %d/%d",
+			 size, LIBUSB_DT_BOS_SIZE);
+		return LIBUSB_ERROR_IO;
+	}
+
+	usbi_parse_descriptor(buffer, "bbwb", &bos_header, host_endian);
+	if (bos_header.bDescriptorType != LIBUSB_DT_BOS) {
+		usbi_err(ctx, "unexpected descriptor %x (expected %x)",
+			 bos_header.bDescriptorType, LIBUSB_DT_BOS);
+		return LIBUSB_ERROR_IO;
+	}
+	if (bos_header.bLength < LIBUSB_DT_BOS_SIZE) {
+		usbi_err(ctx, "invalid bos bLength (%d)", bos_header.bLength);
+		return LIBUSB_ERROR_IO;
+	}
+	if (bos_header.bLength > size) {
+		usbi_err(ctx, "short bos descriptor read %d/%d",
+			 size, bos_header.bLength);
+		return LIBUSB_ERROR_IO;
+	}
+
+	_bos = calloc (1,
+		sizeof(*_bos) + bos_header.bNumDeviceCaps * sizeof(void *));
+	if (!_bos)
+		return LIBUSB_ERROR_NO_MEM;
+
+	usbi_parse_descriptor(buffer, "bbwb", _bos, host_endian);
+	buffer += bos_header.bLength;
+	size -= bos_header.bLength;
+
+	/* Get the device capability descriptors */
+	for (i = 0; i < bos_header.bNumDeviceCaps; i++) {
+		if (size < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) {
+			usbi_warn(ctx, "short dev-cap descriptor read %d/%d",
+				  size, LIBUSB_DT_DEVICE_CAPABILITY_SIZE);
+			break;
+		}
+		usbi_parse_descriptor(buffer, "bbb", &dev_cap, host_endian);
+		if (dev_cap.bDescriptorType != LIBUSB_DT_DEVICE_CAPABILITY) {
+			usbi_warn(ctx, "unexpected descriptor %x (expected %x)",
+				  dev_cap.bDescriptorType, LIBUSB_DT_DEVICE_CAPABILITY);
+			break;
+		}
+		if (dev_cap.bLength < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) {
+			usbi_err(ctx, "invalid dev-cap bLength (%d)",
+				 dev_cap.bLength);
+			libusb_free_bos_descriptor(_bos);
+			return LIBUSB_ERROR_IO;
+		}
+		if (dev_cap.bLength > size) {
+			usbi_warn(ctx, "short dev-cap descriptor read %d/%d",
+				  size, dev_cap.bLength);
+			break;
+		}
+
+		_bos->dev_capability[i] = malloc(dev_cap.bLength);
+		if (!_bos->dev_capability[i]) {
+			libusb_free_bos_descriptor(_bos);
+			return LIBUSB_ERROR_NO_MEM;
+		}
+		memcpy(_bos->dev_capability[i], buffer, dev_cap.bLength);
+		buffer += dev_cap.bLength;
+		size -= dev_cap.bLength;
+	}
+	_bos->bNumDeviceCaps = (uint8_t)i;
+	*bos = _bos;
+
+	return LIBUSB_SUCCESS;
+}
+
+/** \ingroup desc
+ * Get a Binary Object Store (BOS) descriptor
+ * This is a BLOCKING function, which will send requests to the device.
+ *
+ * \param handle the handle of an open libusb device
+ * \param bos output location for the BOS descriptor. Only valid if 0 was returned.
+ * Must be freed with \ref libusb_free_bos_descriptor() after use.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NOT_FOUND if the device doesn't have a BOS descriptor
+ * \returns another LIBUSB_ERROR code on error
+ */
+int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *handle,
+	struct libusb_bos_descriptor **bos)
+{
+	struct libusb_bos_descriptor _bos;
+	uint8_t bos_header[LIBUSB_DT_BOS_SIZE] = {0};
+	unsigned char *bos_data = NULL;
+	const int host_endian = 0;
+	int r;
+
+	/* Read the BOS. This generates 2 requests on the bus,
+	 * one for the header, and one for the full BOS */
+	r = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, bos_header,
+				  LIBUSB_DT_BOS_SIZE);
+	if (r < 0) {
+		if (r != LIBUSB_ERROR_PIPE)
+			usbi_err(handle->dev->ctx, "failed to read BOS (%d)", r);
+		return r;
+	}
+	if (r < LIBUSB_DT_BOS_SIZE) {
+		usbi_err(handle->dev->ctx, "short BOS read %d/%d",
+			 r, LIBUSB_DT_BOS_SIZE);
+		return LIBUSB_ERROR_IO;
+	}
+
+	usbi_parse_descriptor(bos_header, "bbwb", &_bos, host_endian);
+	usbi_dbg("found BOS descriptor: size %d bytes, %d capabilities",
+		 _bos.wTotalLength, _bos.bNumDeviceCaps);
+	bos_data = calloc(_bos.wTotalLength, 1);
+	if (bos_data == NULL)
+		return LIBUSB_ERROR_NO_MEM;
+
+	r = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, bos_data,
+				  _bos.wTotalLength);
+	if (r >= 0)
+		r = parse_bos(handle->dev->ctx, bos, bos_data, r, host_endian);
+	else
+		usbi_err(handle->dev->ctx, "failed to read BOS (%d)", r);
+
+	free(bos_data);
+	return r;
+}
+
+/** \ingroup desc
+ * Free a BOS descriptor obtained from libusb_get_bos_descriptor().
+ * It is safe to call this function with a NULL bos parameter, in which
+ * case the function simply returns.
+ *
+ * \param bos the BOS descriptor to free
+ */
+void API_EXPORTED libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos)
+{
+	int i;
+
+	if (!bos)
+		return;
+
+	for (i = 0; i < bos->bNumDeviceCaps; i++)
+		free(bos->dev_capability[i]);
+	free(bos);
+}
+
+/** \ingroup desc
+ * Get an USB 2.0 Extension descriptor
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param dev_cap Device Capability descriptor with a bDevCapabilityType of
+ * \ref libusb_capability_type::LIBUSB_BT_USB_2_0_EXTENSION
+ * LIBUSB_BT_USB_2_0_EXTENSION
+ * \param usb_2_0_extension output location for the USB 2.0 Extension
+ * descriptor. Only valid if 0 was returned. Must be freed with
+ * libusb_free_usb_2_0_extension_descriptor() after use.
+ * \returns 0 on success
+ * \returns a LIBUSB_ERROR code on error
+ */
+int API_EXPORTED libusb_get_usb_2_0_extension_descriptor(
+	struct libusb_context *ctx,
+	struct libusb_bos_dev_capability_descriptor *dev_cap,
+	struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension)
+{
+	struct libusb_usb_2_0_extension_descriptor *_usb_2_0_extension;
+	const int host_endian = 0;
+
+	if (dev_cap->bDevCapabilityType != LIBUSB_BT_USB_2_0_EXTENSION) {
+		usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)",
+			 dev_cap->bDevCapabilityType,
+			 LIBUSB_BT_USB_2_0_EXTENSION);
+		return LIBUSB_ERROR_INVALID_PARAM;
+	}
+	if (dev_cap->bLength < LIBUSB_BT_USB_2_0_EXTENSION_SIZE) {
+		usbi_err(ctx, "short dev-cap descriptor read %d/%d",
+			 dev_cap->bLength, LIBUSB_BT_USB_2_0_EXTENSION_SIZE);
+		return LIBUSB_ERROR_IO;
+	}
+
+	_usb_2_0_extension = malloc(sizeof(*_usb_2_0_extension));
+	if (!_usb_2_0_extension)
+		return LIBUSB_ERROR_NO_MEM;
+
+	usbi_parse_descriptor((unsigned char *)dev_cap, "bbbd",
+			      _usb_2_0_extension, host_endian);
+
+	*usb_2_0_extension = _usb_2_0_extension;
+	return LIBUSB_SUCCESS;
+}
+
+/** \ingroup desc
+ * Free a USB 2.0 Extension descriptor obtained from
+ * libusb_get_usb_2_0_extension_descriptor().
+ * It is safe to call this function with a NULL usb_2_0_extension parameter,
+ * in which case the function simply returns.
+ *
+ * \param usb_2_0_extension the USB 2.0 Extension descriptor to free
+ */
+void API_EXPORTED libusb_free_usb_2_0_extension_descriptor(
+	struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension)
+{
+	free(usb_2_0_extension);
+}
+
+/** \ingroup desc
+ * Get a SuperSpeed USB Device Capability descriptor
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param dev_cap Device Capability descriptor with a bDevCapabilityType of
+ * \ref libusb_capability_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
+ * LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
+ * \param ss_usb_device_cap output location for the SuperSpeed USB Device
+ * Capability descriptor. Only valid if 0 was returned. Must be freed with
+ * libusb_free_ss_usb_device_capability_descriptor() after use.
+ * \returns 0 on success
+ * \returns a LIBUSB_ERROR code on error
+ */
+int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor(
+	struct libusb_context *ctx,
+	struct libusb_bos_dev_capability_descriptor *dev_cap,
+	struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap)
+{
+	struct libusb_ss_usb_device_capability_descriptor *_ss_usb_device_cap;
+	const int host_endian = 0;
+
+	if (dev_cap->bDevCapabilityType != LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) {
+		usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)",
+			 dev_cap->bDevCapabilityType,
+			 LIBUSB_BT_SS_USB_DEVICE_CAPABILITY);
+		return LIBUSB_ERROR_INVALID_PARAM;
+	}
+	if (dev_cap->bLength < LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) {
+		usbi_err(ctx, "short dev-cap descriptor read %d/%d",
+			 dev_cap->bLength, LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE);
+		return LIBUSB_ERROR_IO;
+	}
+
+	_ss_usb_device_cap = malloc(sizeof(*_ss_usb_device_cap));
+	if (!_ss_usb_device_cap)
+		return LIBUSB_ERROR_NO_MEM;
+
+	usbi_parse_descriptor((unsigned char *)dev_cap, "bbbbwbbw",
+			      _ss_usb_device_cap, host_endian);
+
+	*ss_usb_device_cap = _ss_usb_device_cap;
+	return LIBUSB_SUCCESS;
+}
+
+/** \ingroup desc
+ * Free a SuperSpeed USB Device Capability descriptor obtained from
+ * libusb_get_ss_usb_device_capability_descriptor().
+ * It is safe to call this function with a NULL ss_usb_device_cap
+ * parameter, in which case the function simply returns.
+ *
+ * \param ss_usb_device_cap the USB 2.0 Extension descriptor to free
+ */
+void API_EXPORTED libusb_free_ss_usb_device_capability_descriptor(
+	struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap)
+{
+	free(ss_usb_device_cap);
+}
+
+/** \ingroup desc
+ * Get a Container ID descriptor
+ *
+ * \param ctx the context to operate on, or NULL for the default context
+ * \param dev_cap Device Capability descriptor with a bDevCapabilityType of
+ * \ref libusb_capability_type::LIBUSB_BT_CONTAINER_ID
+ * LIBUSB_BT_CONTAINER_ID
+ * \param container_id output location for the Container ID descriptor.
+ * Only valid if 0 was returned. Must be freed with
+ * libusb_free_container_id_descriptor() after use.
+ * \returns 0 on success
+ * \returns a LIBUSB_ERROR code on error
+ */
+int API_EXPORTED libusb_get_container_id_descriptor(struct libusb_context *ctx,
+	struct libusb_bos_dev_capability_descriptor *dev_cap,
+	struct libusb_container_id_descriptor **container_id)
+{
+	struct libusb_container_id_descriptor *_container_id;
+	const int host_endian = 0;
+
+	if (dev_cap->bDevCapabilityType != LIBUSB_BT_CONTAINER_ID) {
+		usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)",
+			 dev_cap->bDevCapabilityType,
+			 LIBUSB_BT_CONTAINER_ID);
+		return LIBUSB_ERROR_INVALID_PARAM;
+	}
+	if (dev_cap->bLength < LIBUSB_BT_CONTAINER_ID_SIZE) {
+		usbi_err(ctx, "short dev-cap descriptor read %d/%d",
+			 dev_cap->bLength, LIBUSB_BT_CONTAINER_ID_SIZE);
+		return LIBUSB_ERROR_IO;
+	}
+
+	_container_id = malloc(sizeof(*_container_id));
+	if (!_container_id)
+		return LIBUSB_ERROR_NO_MEM;
+
+	usbi_parse_descriptor((unsigned char *)dev_cap, "bbbbu",
+			      _container_id, host_endian);
+
+	*container_id = _container_id;
+	return LIBUSB_SUCCESS;
+}
+
+/** \ingroup desc
+ * Free a Container ID descriptor obtained from
+ * libusb_get_container_id_descriptor().
+ * It is safe to call this function with a NULL container_id parameter,
+ * in which case the function simply returns.
+ *
+ * \param container_id the USB 2.0 Extension descriptor to free
+ */
+void API_EXPORTED libusb_free_container_id_descriptor(
+	struct libusb_container_id_descriptor *container_id)
+{
+	free(container_id);
+}
+
 /** \ingroup desc
 /** \ingroup desc
  * Retrieve a string descriptor in C style ASCII.
  * Retrieve a string descriptor in C style ASCII.
  *
  *
@@ -748,7 +1188,7 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev,
 		if (di >= (length - 1))
 		if (di >= (length - 1))
 			break;
 			break;
 
 
-		if (tbuf[si + 1]) /* high byte */
+		if ((tbuf[si] & 0x80) || (tbuf[si + 1])) /* non-ASCII */
 			data[di++] = '?';
 			data[di++] = '?';
 		else
 		else
 			data[di++] = tbuf[si];
 			data[di++] = tbuf[si];
@@ -757,116 +1197,3 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev,
 	data[di] = 0;
 	data[di] = 0;
 	return di;
 	return di;
 }
 }
-
-int API_EXPORTED libusb_parse_ss_endpoint_comp(const void *buf, int len,
-					       struct libusb_ss_endpoint_companion_descriptor **ep_comp)
-{
-	struct libusb_ss_endpoint_companion_descriptor *ep_comp_desc;
-	struct usb_descriptor_header header;
-
-	usbi_parse_descriptor(buf, "bb", &header, 0);
-
-	/* Everything should be fine being passed into here, but we sanity */
-	/*  check JIC */
-	if (header.bLength > len) {
-		usbi_err(NULL, "ran out of descriptors parsing");
-		return LIBUSB_ERROR_NO_MEM;
-	}
-
-	if (header.bDescriptorType != LIBUSB_DT_SS_ENDPOINT_COMPANION) {
-		usbi_err(NULL, "unexpected descriptor %x (expected %x)",
-			header.bDescriptorType, LIBUSB_DT_SS_ENDPOINT_COMPANION);
-		return LIBUSB_ERROR_INVALID_PARAM;
-	}
-
-	ep_comp_desc = calloc(1, sizeof (*ep_comp_desc));
-	if (!ep_comp_desc) {
-		return LIBUSB_ERROR_NO_MEM;
-	}
-
-	if (header.bLength >= LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE)
-		usbi_parse_descriptor(buf, "bbbbw", ep_comp_desc, 0);
-
-	*ep_comp = ep_comp_desc;
-
-	return LIBUSB_SUCCESS;
-}
-
-void API_EXPORTED libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp)
-{
-	assert(ep_comp);
-	free(ep_comp);
-}
-
-int API_EXPORTED libusb_parse_bos_descriptor(const void *buf, int len,
-                                             struct libusb_bos_descriptor **bos)
-{
-	const unsigned char *buffer = (const unsigned char *) buf;
-	struct libusb_bos_descriptor *bos_desc;
-	int i;
-
-	len = len;
-	bos_desc = calloc (1, sizeof (*bos_desc));
-	if (!bos_desc) {
-		return LIBUSB_ERROR_NO_MEM;
-	}
-
-	usbi_parse_descriptor(buffer, "bbwb", bos_desc, 0);
-	buffer += LIBUSB_DT_BOS_SIZE;
-
-	/* Get the device capability descriptors */
-	for (i = 0; i < bos_desc->bNumDeviceCaps; ++i) {
-		if (buffer[2] == LIBUSB_USB_CAP_TYPE_EXT) {
-			if (!bos_desc->usb_2_0_ext_cap) {
-				bos_desc->usb_2_0_ext_cap =
-					(struct libusb_usb_2_0_device_capability_descriptor *)
-					malloc(sizeof(*bos_desc->usb_2_0_ext_cap));
-				usbi_parse_descriptor(buffer, "bbbd",
-						      bos_desc->usb_2_0_ext_cap, 0);
-			} else
-				usbi_warn(NULL,
-					  "usb_2_0_ext_cap was already allocated");
-
-			/* move to the next device capability descriptor */
-			buffer += LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE;
-		} else if (buffer[2] == LIBUSB_SS_USB_CAP_TYPE) {
-			if (!bos_desc->ss_usb_cap) {
-				bos_desc->ss_usb_cap =
-					(struct libusb_ss_usb_device_capability_descriptor *)
-					malloc(sizeof(*bos_desc->ss_usb_cap));
-				usbi_parse_descriptor(buffer, "bbbbwbbw",
-						      bos_desc->ss_usb_cap, 0);
-			} else
-				usbi_warn(NULL,
-					  "ss_usb_cap was already allocated");
-
-			/* move to the next device capability descriptor */
-			buffer += LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE;
-		} else {
-			usbi_info(NULL, "wireless/container_id capability "
-				  "descriptor");
-
-			/* move to the next device capability descriptor */
-			buffer += buffer[0];
-		}
-	}
-
-	*bos = bos_desc;
-
-	return LIBUSB_SUCCESS;
-}
-
-void API_EXPORTED libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos)
-{
-	assert(bos);
-
-	if (bos->usb_2_0_ext_cap) {
-		free(bos->usb_2_0_ext_cap);
-	}
-
-	if (bos->ss_usb_cap) {
-		free(bos->ss_usb_cap);
-	}
-
-	free(bos);
-}

+ 165 - 141
compat/libusb-1.0/libusb/hotplug.c

@@ -1,8 +1,8 @@
-/* -*- Mode: C; indent-tabs-mode:nil ; c-basic-offset:8 -*- */
+/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
 /*
 /*
- * Hotplug functions for libusb
- * Copyright (C) 2012-2013 Nathan Hjelm <hjelmn@mac.com>
- * Copyright (C) 2012-2013 Peter Stuge <peter@stuge.se>
+ * Hotplug functions for libusbx
+ * Copyright © 2012-2013 Nathan Hjelm <hjelmn@mac.com>
+ * Copyright © 2012-2013 Peter Stuge <peter@stuge.se>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -25,7 +25,9 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
+#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #include <sys/types.h>
+#endif
 #include <assert.h>
 #include <assert.h>
 
 
 #include "libusbi.h"
 #include "libusbi.h"
@@ -33,27 +35,39 @@
 
 
 /**
 /**
  * @defgroup hotplug  Device hotplug event notification
  * @defgroup hotplug  Device hotplug event notification
- * This page details how to use the libusb hotplug interface.
+ * This page details how to use the libusb hotplug interface, where available.
+ *
+ * Be mindful that not all platforms currently implement hotplug notification and
+ * that you should first call on \ref libusb_has_capability() with parameter
+ * \ref LIBUSB_CAP_HAS_HOTPLUG to confirm that hotplug support is available.
  *
  *
  * \page hotplug Device hotplug event notification
  * \page hotplug Device hotplug event notification
  *
  *
  * \section intro Introduction
  * \section intro Introduction
  *
  *
- * Releases of libusb 1.0 newer than 1.X have added support for hotplug
- * events. This interface allows you to request notification for the
- * arrival and departure of matching USB devices.
+ * Version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102, has added support
+ * for hotplug events on <b>some</b> platforms (you should test if your platform
+ * supports hotplug notification by calling \ref libusb_has_capability() with
+ * parameter \ref LIBUSB_CAP_HAS_HOTPLUG). 
+ *
+ * This interface allows you to request notification for the arrival and departure
+ * of matching USB devices.
  *
  *
  * To receive hotplug notification you register a callback by calling
  * To receive hotplug notification you register a callback by calling
- * libusb_hotplug_register_callback(). This function will optionally return
- * a handle that can be passed to libusb_hotplug_deregister_callback().
+ * \ref libusb_hotplug_register_callback(). This function will optionally return
+ * a handle that can be passed to \ref libusb_hotplug_deregister_callback().
  *
  *
  * A callback function must return an int (0 or 1) indicating whether the callback is
  * A callback function must return an int (0 or 1) indicating whether the callback is
  * expecting additional events. Returning 0 will rearm the callback and 1 will cause
  * expecting additional events. Returning 0 will rearm the callback and 1 will cause
- * the callback to be deregistered.
+ * the callback to be deregistered. Note that when callbacks are called from
+ * libusb_hotplug_register_callback() because of the \ref LIBUSB_HOTPLUG_ENUMERATE
+ * flag, the callback return value is ignored, iow you cannot cause a callback
+ * to be deregistered by returning 1 when it is called from
+ * libusb_hotplug_register_callback().
  *
  *
- * Callbacks for a particulat context are automatically deregistered by libusb_exit().
+ * Callbacks for a particular context are automatically deregistered by libusb_exit().
  *
  *
- * As of 1.X there are two supported hotplug events:
+ * As of 1.0.16 there are two supported hotplug events:
  *  - LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: A device has arrived and is ready to use
  *  - LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: A device has arrived and is ready to use
  *  - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: A device has left and is no longer available
  *  - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: A device has left and is no longer available
  *
  *
@@ -66,7 +80,7 @@
  * are invalid and will remain so even if the device comes back.
  * are invalid and will remain so even if the device comes back.
  *
  *
  * When handling a LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED event it is considered
  * When handling a LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED event it is considered
- * safe to call any libusb function that takes a libusb_device. On the other hand,
+ * safe to call any libusbx function that takes a libusb_device. On the other hand,
  * when handling a LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT event the only safe function
  * when handling a LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT event the only safe function
  * is libusb_get_device_descriptor().
  * is libusb_get_device_descriptor().
  *
  *
@@ -128,160 +142,170 @@ int main (void) {
 \endcode
 \endcode
  */
  */
 
 
-static int usbi_hotplug_match_cb (struct libusb_device *dev, libusb_hotplug_event event,
-                                   struct libusb_hotplug_callback *hotplug_cb) {
-	struct libusb_context *ctx = dev->ctx;
-
-        /* Handle lazy deregistration of callback */
-        if (hotplug_cb->needs_free) {
-                /* Free callback */
-                return 1;
-        }
-
-        if (!(hotplug_cb->events & event)) {
-                return 0;
-        }
-
-        if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->vendor_id &&
-            hotplug_cb->vendor_id != dev->device_descriptor.idVendor) {
-                return 0;
-        }
-
-        if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->product_id &&
-            hotplug_cb->product_id != dev->device_descriptor.idProduct) {
-                return 0;
-        }
-
-        if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->dev_class &&
-            hotplug_cb->dev_class != dev->device_descriptor.bDeviceClass) {
-                return 0;
-        }
-
-        return hotplug_cb->cb (ctx == usbi_default_context ? NULL : ctx,
-                             dev, event, hotplug_cb->user_data);
+static int usbi_hotplug_match_cb (struct libusb_context *ctx,
+	struct libusb_device *dev, libusb_hotplug_event event,
+	struct libusb_hotplug_callback *hotplug_cb)
+{
+	/* Handle lazy deregistration of callback */
+	if (hotplug_cb->needs_free) {
+		/* Free callback */
+		return 1;
+	}
+
+	if (!(hotplug_cb->events & event)) {
+		return 0;
+	}
+
+	if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->vendor_id &&
+	    hotplug_cb->vendor_id != dev->device_descriptor.idVendor) {
+		return 0;
+	}
+
+	if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->product_id &&
+	    hotplug_cb->product_id != dev->device_descriptor.idProduct) {
+		return 0;
+	}
+
+	if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->dev_class &&
+	    hotplug_cb->dev_class != dev->device_descriptor.bDeviceClass) {
+		return 0;
+	}
+
+	return hotplug_cb->cb (ctx, dev, event, hotplug_cb->user_data);
 }
 }
 
 
-void usbi_hotplug_match(struct libusb_device *dev, libusb_hotplug_event event) {
+void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
+	libusb_hotplug_event event)
+{
 	struct libusb_hotplug_callback *hotplug_cb, *next;
 	struct libusb_hotplug_callback *hotplug_cb, *next;
-	struct libusb_context *ctx = dev->ctx;
+	int ret;
 
 
 	usbi_mutex_lock(&ctx->hotplug_cbs_lock);
 	usbi_mutex_lock(&ctx->hotplug_cbs_lock);
 
 
 	list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
 	list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
-                usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
-                int ret = usbi_hotplug_match_cb (dev, event, hotplug_cb);
-                usbi_mutex_lock(&ctx->hotplug_cbs_lock);
-
-                if (ret) {
-                        list_del(&hotplug_cb->list);
-                        free(hotplug_cb);
-                }
+		usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
+		ret = usbi_hotplug_match_cb (ctx, dev, event, hotplug_cb);
+		usbi_mutex_lock(&ctx->hotplug_cbs_lock);
+
+		if (ret) {
+			list_del(&hotplug_cb->list);
+			free(hotplug_cb);
+		}
 	}
 	}
 
 
 	usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
 	usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
 
 
-        /* loop through and disconnect all open handles for this device */
-        if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) {
-                struct libusb_device_handle *handle;
-
-                usbi_mutex_lock(&ctx->open_devs_lock);
-                list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
-                        if (dev == handle->dev) {
-                                usbi_handle_disconnect (handle);
-                        }
-                }
-                usbi_mutex_unlock(&ctx->open_devs_lock);
-        }
+	/* the backend is expected to call the callback for each active transfer */
 }
 }
 
 
 int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
 int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
-                                                  libusb_hotplug_event events,
-                                                  libusb_hotplug_flag flags,
-                                                  int vendor_id, int product_id,
-                                                  int dev_class,
-                                                  libusb_hotplug_callback_fn cb_fn,
-                                                  void *user_data, libusb_hotplug_callback_handle *handle) {
-        libusb_hotplug_callback *new_callback;
-        static int handle_id = 1;
-
-        /* check for hotplug support */
-        if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
-                return LIBUSB_ERROR_NOT_SUPPORTED;
-        }
-
-        /* check for sane values */
-        if ((LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) ||
-            (LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) ||
-            (LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) ||
-            !cb_fn) {
-                return LIBUSB_ERROR_INVALID_PARAM;
-        }
-
-        USBI_GET_CONTEXT(ctx);
-
-        new_callback = (libusb_hotplug_callback *)calloc(1, sizeof (*new_callback));
-        if (!new_callback) {
-                return LIBUSB_ERROR_NO_MEM;
-        }
-
-        new_callback->ctx = ctx;
-        new_callback->vendor_id = vendor_id;
-        new_callback->product_id = product_id;
-        new_callback->dev_class = dev_class;
-        new_callback->flags = flags;
-        new_callback->events = events;
-        new_callback->cb = cb_fn;
-        new_callback->user_data = user_data;
-        new_callback->needs_free = 0;
+	libusb_hotplug_event events, libusb_hotplug_flag flags,
+	int vendor_id, int product_id, int dev_class,
+	libusb_hotplug_callback_fn cb_fn, void *user_data,
+	libusb_hotplug_callback_handle *handle)
+{
+	libusb_hotplug_callback *new_callback;
+	static int handle_id = 1;
+
+	/* check for hotplug support */
+	if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+		return LIBUSB_ERROR_NOT_SUPPORTED;
+	}
+
+	/* check for sane values */
+	if ((LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) ||
+	    (LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) ||
+	    (LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) ||
+	    !cb_fn) {
+		return LIBUSB_ERROR_INVALID_PARAM;
+	}
+
+	USBI_GET_CONTEXT(ctx);
+
+	new_callback = (libusb_hotplug_callback *)calloc(1, sizeof (*new_callback));
+	if (!new_callback) {
+		return LIBUSB_ERROR_NO_MEM;
+	}
+
+	new_callback->ctx = ctx;
+	new_callback->vendor_id = vendor_id;
+	new_callback->product_id = product_id;
+	new_callback->dev_class = dev_class;
+	new_callback->flags = flags;
+	new_callback->events = events;
+	new_callback->cb = cb_fn;
+	new_callback->user_data = user_data;
+	new_callback->needs_free = 0;
 
 
 	usbi_mutex_lock(&ctx->hotplug_cbs_lock);
 	usbi_mutex_lock(&ctx->hotplug_cbs_lock);
 
 
-        /* protect the handle by the context hotplug lock. it doesn't matter if the same handle is used for different
-           contexts only that the handle is unique for this context */
-        new_callback->handle = handle_id++;
+	/* protect the handle by the context hotplug lock. it doesn't matter if the same handle
+	 * is used for different contexts only that the handle is unique for this context */
+	new_callback->handle = handle_id++;
 
 
 	list_add(&new_callback->list, &ctx->hotplug_cbs);
 	list_add(&new_callback->list, &ctx->hotplug_cbs);
 
 
-        if (flags & LIBUSB_HOTPLUG_ENUMERATE) {
-                struct libusb_device *dev;
+	usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
 
 
-                usbi_mutex_lock(&ctx->usb_devs_lock);
 
 
-                list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) {
-                        (void) usbi_hotplug_match_cb (dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, new_callback);
-                }
+	if (flags & LIBUSB_HOTPLUG_ENUMERATE) {
+		int i, len;
+		struct libusb_device **devs;
 
 
-                usbi_mutex_unlock(&ctx->usb_devs_lock);
-        }
+		len = (int) libusb_get_device_list(ctx, &devs);
+		if (len < 0) {
+			libusb_hotplug_deregister_callback(ctx,
+							new_callback->handle);
+			return len;
+		}
 
 
-	usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
+		for (i = 0; i < len; i++) {
+			usbi_hotplug_match_cb(ctx, devs[i],
+					LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
+					new_callback);
+		}
 
 
-        if (handle) {
-                *handle = new_callback->handle;
-        }
+		libusb_free_device_list(devs, 1);
+	}
 
 
-        return LIBUSB_SUCCESS;
+
+	if (handle) {
+		*handle = new_callback->handle;
+	}
+
+	return LIBUSB_SUCCESS;
 }
 }
 
 
-void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx, libusb_hotplug_callback_handle handle) {
-        struct libusb_hotplug_callback *hotplug_cb;
-
-        /* check for hotplug support */
-        if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
-                return;
-        }
-
-        USBI_GET_CONTEXT(ctx);
-
-        usbi_mutex_lock(&ctx->hotplug_cbs_lock);
-        list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list,
-                            struct libusb_hotplug_callback) {
-                if (handle == hotplug_cb->handle) {
-                        /* Mark this callback for deregistration */
-                        hotplug_cb->needs_free = 1;
-                }
-        }
-        usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
+void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx,
+	libusb_hotplug_callback_handle handle)
+{
+	struct libusb_hotplug_callback *hotplug_cb;
+	libusb_hotplug_message message;
+	ssize_t ret;
+
+	/* check for hotplug support */
+	if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+		return;
+	}
+
+	USBI_GET_CONTEXT(ctx);
+
+	usbi_mutex_lock(&ctx->hotplug_cbs_lock);
+	list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list,
+			    struct libusb_hotplug_callback) {
+		if (handle == hotplug_cb->handle) {
+			/* Mark this callback for deregistration */
+			hotplug_cb->needs_free = 1;
+		}
+	}
+	usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
+
+	/* wakeup handle_events to do the actual free */
+	memset(&message, 0, sizeof(message));
+	ret = usbi_write(ctx->hotplug_pipe[1], &message, sizeof(message));
+	if (sizeof(message) != ret) {
+		usbi_err(ctx, "error writing hotplug message");
+	}
 }
 }
 
 
 void usbi_hotplug_deregister_all(struct libusb_context *ctx) {
 void usbi_hotplug_deregister_all(struct libusb_context *ctx) {
@@ -291,7 +315,7 @@ void usbi_hotplug_deregister_all(struct libusb_context *ctx) {
 	list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list,
 	list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list,
 				 struct libusb_hotplug_callback) {
 				 struct libusb_hotplug_callback) {
 		list_del(&hotplug_cb->list);
 		list_del(&hotplug_cb->list);
-                free(hotplug_cb);
+		free(hotplug_cb);
 	}
 	}
 
 
 	usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
 	usbi_mutex_unlock(&ctx->hotplug_cbs_lock);

+ 18 - 13
compat/libusb-1.0/libusb/hotplug.h

@@ -1,8 +1,8 @@
-/* -*- Mode: C; indent-tabs-mode:nil ; c-basic-offset:8 -*- */
+/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
 /*
 /*
- * Hotplug support for libusb 1.0
- * Copyright (C) 2012      Nathan Hjelm <hjelmn@users.sourceforge.net>
- * Copyright (C) 2012      Peter Stuge <peter@stuge.se>
+ * Hotplug support for libusbx
+ * Copyright © 2012-2013 Nathan Hjelm <hjelmn@mac.com>
+ * Copyright © 2012-2013 Peter Stuge <peter@stuge.se>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -22,6 +22,10 @@
 #if !defined(USBI_HOTPLUG_H)
 #if !defined(USBI_HOTPLUG_H)
 #define USBI_HOTPLUG_H
 #define USBI_HOTPLUG_H
 
 
+#ifndef LIBUSBI_H
+#include "libusbi.h"
+#endif
+
 /** \ingroup hotplug
 /** \ingroup hotplug
  * The hotplug callback structure. The user populates this structure with
  * The hotplug callback structure. The user populates this structure with
  * libusb_hotplug_prepare_callback() and then calls libusb_hotplug_register_callback()
  * libusb_hotplug_prepare_callback() and then calls libusb_hotplug_register_callback()
@@ -41,7 +45,7 @@ struct libusb_hotplug_callback {
 	int dev_class;
 	int dev_class;
 
 
 	/** Hotplug callback flags */
 	/** Hotplug callback flags */
-        libusb_hotplug_flag flags;
+	libusb_hotplug_flag flags;
 
 
 	/** Event(s) that will trigger this callback */
 	/** Event(s) that will trigger this callback */
 	libusb_hotplug_event events;
 	libusb_hotplug_event events;
@@ -49,29 +53,30 @@ struct libusb_hotplug_callback {
 	/** Callback function to invoke for matching event/device */
 	/** Callback function to invoke for matching event/device */
 	libusb_hotplug_callback_fn cb;
 	libusb_hotplug_callback_fn cb;
 
 
-        /** Handle for this callback (used to match on deregister) */
-        libusb_hotplug_callback_handle handle;
+	/** Handle for this callback (used to match on deregister) */
+	libusb_hotplug_callback_handle handle;
 
 
 	/** User data that will be passed to the callback function */
 	/** User data that will be passed to the callback function */
 	void *user_data;
 	void *user_data;
 
 
-        /** Callback is marked for deletion */
-        int needs_free;
+	/** Callback is marked for deletion */
+	int needs_free;
 
 
 	/** List this callback is registered in (ctx->hotplug_cbs) */
 	/** List this callback is registered in (ctx->hotplug_cbs) */
-        struct list_head list;
+	struct list_head list;
 };
 };
 
 
 typedef struct libusb_hotplug_callback libusb_hotplug_callback;
 typedef struct libusb_hotplug_callback libusb_hotplug_callback;
 
 
 struct libusb_hotplug_message {
 struct libusb_hotplug_message {
-        libusb_hotplug_event event;
-        struct libusb_device *device;
+	libusb_hotplug_event event;
+	struct libusb_device *device;
 };
 };
 
 
 typedef struct libusb_hotplug_message libusb_hotplug_message;
 typedef struct libusb_hotplug_message libusb_hotplug_message;
 
 
 void usbi_hotplug_deregister_all(struct libusb_context *ctx);
 void usbi_hotplug_deregister_all(struct libusb_context *ctx);
-void usbi_hotplug_match(struct libusb_device *dev, libusb_hotplug_event event);
+void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
+			libusb_hotplug_event event);
 
 
 #endif
 #endif

File diff suppressed because it is too large
+ 276 - 221
compat/libusb-1.0/libusb/io.c


+ 39 - 1
compat/libusb-1.0/libusb/libusb-1.0.def

@@ -1,4 +1,4 @@
-LIBRARY
+LIBRARY "libusb-1.0.dll"
 EXPORTS
 EXPORTS
   libusb_alloc_transfer
   libusb_alloc_transfer
   libusb_alloc_transfer@4 = libusb_alloc_transfer
   libusb_alloc_transfer@4 = libusb_alloc_transfer
@@ -26,14 +26,26 @@ EXPORTS
   libusb_event_handling_ok@4 = libusb_event_handling_ok
   libusb_event_handling_ok@4 = libusb_event_handling_ok
   libusb_exit
   libusb_exit
   libusb_exit@4 = libusb_exit
   libusb_exit@4 = libusb_exit
+  libusb_free_bos_descriptor
+  libusb_free_bos_descriptor@4 = libusb_free_bos_descriptor
   libusb_free_config_descriptor
   libusb_free_config_descriptor
   libusb_free_config_descriptor@4 = libusb_free_config_descriptor
   libusb_free_config_descriptor@4 = libusb_free_config_descriptor
+  libusb_free_container_id_descriptor
+  libusb_free_container_id_descriptor@4 = libusb_free_container_id_descriptor
   libusb_free_device_list
   libusb_free_device_list
   libusb_free_device_list@8 = libusb_free_device_list
   libusb_free_device_list@8 = libusb_free_device_list
+  libusb_free_ss_endpoint_companion_descriptor
+  libusb_free_ss_endpoint_companion_descriptor@4 = libusb_free_ss_endpoint_companion_descriptor
+  libusb_free_ss_usb_device_capability_descriptor
+  libusb_free_ss_usb_device_capability_descriptor@4 = libusb_free_ss_usb_device_capability_descriptor
   libusb_free_transfer
   libusb_free_transfer
   libusb_free_transfer@4 = libusb_free_transfer
   libusb_free_transfer@4 = libusb_free_transfer
+  libusb_free_usb_2_0_extension_descriptor
+  libusb_free_usb_2_0_extension_descriptor@4 = libusb_free_usb_2_0_extension_descriptor
   libusb_get_active_config_descriptor
   libusb_get_active_config_descriptor
   libusb_get_active_config_descriptor@8 = libusb_get_active_config_descriptor
   libusb_get_active_config_descriptor@8 = libusb_get_active_config_descriptor
+  libusb_get_bos_descriptor
+  libusb_get_bos_descriptor@8 = libusb_get_bos_descriptor
   libusb_get_bus_number
   libusb_get_bus_number
   libusb_get_bus_number@4 = libusb_get_bus_number
   libusb_get_bus_number@4 = libusb_get_bus_number
   libusb_get_config_descriptor
   libusb_get_config_descriptor
@@ -42,6 +54,8 @@ EXPORTS
   libusb_get_config_descriptor_by_value@12 = 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
   libusb_get_configuration@8 = libusb_get_configuration
   libusb_get_configuration@8 = libusb_get_configuration
+  libusb_get_container_id_descriptor
+  libusb_get_container_id_descriptor@12 = libusb_get_container_id_descriptor
   libusb_get_device
   libusb_get_device
   libusb_get_device@4 = libusb_get_device
   libusb_get_device@4 = libusb_get_device
   libusb_get_device_address
   libusb_get_device_address
@@ -58,10 +72,24 @@ EXPORTS
   libusb_get_max_packet_size@8 = libusb_get_max_packet_size
   libusb_get_max_packet_size@8 = libusb_get_max_packet_size
   libusb_get_next_timeout
   libusb_get_next_timeout
   libusb_get_next_timeout@8 = libusb_get_next_timeout
   libusb_get_next_timeout@8 = libusb_get_next_timeout
+  libusb_get_parent
+  libusb_get_parent@4 = libusb_get_parent
   libusb_get_pollfds
   libusb_get_pollfds
   libusb_get_pollfds@4 = libusb_get_pollfds
   libusb_get_pollfds@4 = libusb_get_pollfds
+  libusb_get_port_number
+  libusb_get_port_number@4 = libusb_get_port_number
+  libusb_get_port_numbers
+  libusb_get_port_numbers@12 = libusb_get_port_numbers
+  libusb_get_port_path
+  libusb_get_port_path@16 = libusb_get_port_path
+  libusb_get_ss_endpoint_companion_descriptor
+  libusb_get_ss_endpoint_companion_descriptor@12 = libusb_get_ss_endpoint_companion_descriptor
+  libusb_get_ss_usb_device_capability_descriptor
+  libusb_get_ss_usb_device_capability_descriptor@12 = libusb_get_ss_usb_device_capability_descriptor
   libusb_get_string_descriptor_ascii
   libusb_get_string_descriptor_ascii
   libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii
   libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii
+  libusb_get_usb_2_0_extension_descriptor
+  libusb_get_usb_2_0_extension_descriptor@12 = libusb_get_usb_2_0_extension_descriptor
   libusb_get_version
   libusb_get_version
   libusb_get_version@0 = libusb_get_version
   libusb_get_version@0 = libusb_get_version
   libusb_handle_events
   libusb_handle_events
@@ -76,6 +104,10 @@ EXPORTS
   libusb_handle_events_timeout_completed@12 = libusb_handle_events_timeout_completed
   libusb_handle_events_timeout_completed@12 = libusb_handle_events_timeout_completed
   libusb_has_capability
   libusb_has_capability
   libusb_has_capability@4 = libusb_has_capability
   libusb_has_capability@4 = libusb_has_capability
+  libusb_hotplug_deregister_callback
+  libusb_hotplug_deregister_callback@8 = libusb_hotplug_deregister_callback
+  libusb_hotplug_register_callback
+  libusb_hotplug_register_callback@36 = libusb_hotplug_register_callback
   libusb_init
   libusb_init
   libusb_init@4 = libusb_init
   libusb_init@4 = libusb_init
   libusb_interrupt_transfer
   libusb_interrupt_transfer
@@ -98,6 +130,8 @@ EXPORTS
   libusb_release_interface@8 = libusb_release_interface
   libusb_release_interface@8 = libusb_release_interface
   libusb_reset_device
   libusb_reset_device
   libusb_reset_device@4 = libusb_reset_device
   libusb_reset_device@4 = libusb_reset_device
+  libusb_set_auto_detach_kernel_driver
+  libusb_set_auto_detach_kernel_driver@8 = libusb_set_auto_detach_kernel_driver
   libusb_set_configuration
   libusb_set_configuration
   libusb_set_configuration@8 = libusb_set_configuration
   libusb_set_configuration@8 = libusb_set_configuration
   libusb_set_debug
   libusb_set_debug
@@ -106,6 +140,10 @@ EXPORTS
   libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting
   libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting
   libusb_set_pollfd_notifiers
   libusb_set_pollfd_notifiers
   libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers
   libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers
+  libusb_setlocale
+  libusb_setlocale@4 = libusb_setlocale
+  libusb_strerror
+  libusb_strerror@4 = libusb_strerror
   libusb_submit_transfer
   libusb_submit_transfer
   libusb_submit_transfer@4 = libusb_submit_transfer
   libusb_submit_transfer@4 = libusb_submit_transfer
   libusb_try_lock_events
   libusb_try_lock_events

+ 9 - 4
compat/libusb-1.0/libusb/libusb-1.0.rc

@@ -5,16 +5,22 @@
  * The information can then be queried using standard APIs and can also be
  * The information can then be queried using standard APIs and can also be
  * viewed with utilities such as Windows Explorer.
  * viewed with utilities such as Windows Explorer.
  */
  */
+#ifndef _WIN32_WCE
 #include "winresrc.h"
 #include "winresrc.h"
+#endif
 
 
 #include "version.h"
 #include "version.h"
 #ifndef LIBUSB_VERSIONSTRING
 #ifndef LIBUSB_VERSIONSTRING
 #define LU_STR(s) #s
 #define LU_STR(s) #s
 #define LU_XSTR(s) LU_STR(s)
 #define LU_XSTR(s) LU_STR(s)
 #if LIBUSB_NANO > 0
 #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"
+#define LIBUSB_VERSIONSTRING \
+	LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." \
+	LU_XSTR(LIBUSB_MICRO) "." LU_XSTR(LIBUSB_NANO) LIBUSB_RC "\0"
 #else
 #else
-#define LIBUSB_VERSIONSTRING LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." LU_XSTR(LIBUSB_MICRO) LIBUSB_RC "\0"
+#define LIBUSB_VERSIONSTRING \
+	LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." \
+	LU_XSTR(LIBUSB_MICRO) LIBUSB_RC "\0"
 #endif
 #endif
 #endif
 #endif
 
 
@@ -35,8 +41,7 @@ BEGIN
 	BEGIN
 	BEGIN
 		BLOCK "040904b0"
 		BLOCK "040904b0"
 		BEGIN
 		BEGIN
-			VALUE "Comments", "\0"
-			VALUE "CompanyName", "libusb.org\0"
+			VALUE "CompanyName", "libusbx.org\0"
 			VALUE "FileDescription", "C library for writing portable USB drivers in userspace\0"
 			VALUE "FileDescription", "C library for writing portable USB drivers in userspace\0"
 			VALUE "FileVersion", LIBUSB_VERSIONSTRING
 			VALUE "FileVersion", LIBUSB_VERSIONSTRING
 			VALUE "InternalName", "libusb\0"
 			VALUE "InternalName", "libusb\0"

File diff suppressed because it is too large
+ 351 - 191
compat/libusb-1.0/libusb/libusb.h


+ 158 - 125
compat/libusb-1.0/libusb/libusbi.h

@@ -1,7 +1,7 @@
 /*
 /*
- * Internal header for libusb
- * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
- * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ * Internal header for libusbx
+ * Copyright © 2007-2009 Daniel Drake <dsd@gentoo.org>
+ * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -21,7 +21,9 @@
 #ifndef LIBUSBI_H
 #ifndef LIBUSBI_H
 #define LIBUSBI_H
 #define LIBUSBI_H
 
 
-#include <config.h>
+#include "config.h"
+
+#include <stdlib.h>
 
 
 #include <stddef.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdint.h>
@@ -31,14 +33,17 @@
 #include <poll.h>
 #include <poll.h>
 #endif
 #endif
 
 
-#include <libusb.h>
-#include <version.h>
+#ifdef HAVE_MISSING_H
+#include "missing.h"
+#endif
+#include "libusb.h"
+#include "version.h"
 
 
-/* Inside the libusb code, mark all public functions as follows:
+/* Inside the libusbx code, mark all public functions as follows:
  *   return_type API_EXPORTED function_name(params) { ... }
  *   return_type API_EXPORTED function_name(params) { ... }
  * But if the function returns a pointer, mark it as follows:
  * But if the function returns a pointer, mark it as follows:
  *   DEFAULT_VISIBILITY return_type * LIBUSB_CALL function_name(params) { ... }
  *   DEFAULT_VISIBILITY return_type * LIBUSB_CALL function_name(params) { ... }
- * In the libusb public header, mark all declarations as:
+ * In the libusbx public header, mark all declarations as:
  *   return_type LIBUSB_CALL function_name(params);
  *   return_type LIBUSB_CALL function_name(params);
  */
  */
 #define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY
 #define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY
@@ -49,34 +54,50 @@
 #define USB_MAXINTERFACES	32
 #define USB_MAXINTERFACES	32
 #define USB_MAXCONFIG		8
 #define USB_MAXCONFIG		8
 
 
+/* Backend specific capabilities */
+#define USBI_CAP_HAS_HID_ACCESS					0x00010000
+#define USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER	0x00020000
+
+/* Maximum number of bytes in a log line */
+#define USBI_MAX_LOG_LEN	1024
+/* Terminator for log lines */
+#define USBI_LOG_LINE_END	"\n"
+
+/* The following is used to silence warnings for unused variables */
+#define UNUSED(var)			do { (void)(var); } while(0)
+
+#if !defined(ARRAYSIZE)
+#define ARRAYSIZE(array) (sizeof(array)/sizeof(array[0]))
+#endif
+
 struct list_head {
 struct list_head {
 	struct list_head *prev, *next;
 	struct list_head *prev, *next;
 };
 };
 
 
 /* Get an entry from the list
 /* 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"
+ *  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) \
 #define list_entry(ptr, type, member) \
-	((type *)((uintptr_t)(ptr) - (uintptr_t)(&((type *)0L)->member)))
+	((type *)((uintptr_t)(ptr) - (uintptr_t)offsetof(type, member)))
 
 
 /* Get each entry from a list
 /* 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
+ *  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)			\
 #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))
+	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_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))
 #define list_empty(entry) ((entry)->next == (entry))
 
 
@@ -108,6 +129,15 @@ static inline void list_del(struct list_head *entry)
 {
 {
 	entry->next->prev = entry->prev;
 	entry->next->prev = entry->prev;
 	entry->prev->next = entry->next;
 	entry->prev->next = entry->next;
+	entry->next = entry->prev = NULL;
+}
+
+static inline void *usbi_reallocf(void *ptr, size_t size)
+{
+	void *ret = realloc(ptr, size);
+	if (!ret)
+		free(ptr);
+	return ret;
 }
 }
 
 
 #define container_of(ptr, type, member) ({                      \
 #define container_of(ptr, type, member) ({                      \
@@ -119,93 +149,52 @@ static inline void list_del(struct list_head *entry)
 
 
 #define TIMESPEC_IS_SET(ts) ((ts)->tv_sec != 0 || (ts)->tv_nsec != 0)
 #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,
+void usbi_log(struct libusb_context *ctx, enum libusb_log_level level,
 	const char *function, const char *format, ...);
 	const char *function, const char *format, ...);
 
 
-void usbi_log_v(struct libusb_context *ctx, enum usbi_log_level level,
+void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
 	const char *function, const char *format, va_list args);
 	const char *function, const char *format, va_list args);
 
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1400
 #if !defined(_MSC_VER) || _MSC_VER >= 1400
 
 
 #ifdef ENABLE_LOGGING
 #ifdef ENABLE_LOGGING
 #define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__)
 #define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__)
+#define usbi_dbg(...) _usbi_log(NULL, LIBUSB_LOG_LEVEL_DEBUG, __VA_ARGS__)
 #else
 #else
 #define _usbi_log(ctx, level, ...) do { (void)(ctx); } while(0)
 #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)
 #define usbi_dbg(...) do {} while(0)
 #endif
 #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__)
+#define usbi_info(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_INFO, __VA_ARGS__)
+#define usbi_warn(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_WARNING, __VA_ARGS__)
+#define usbi_err(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_ERROR, __VA_ARGS__)
 
 
 #else /* !defined(_MSC_VER) || _MSC_VER >= 1400 */
 #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
 #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
+#define LOG_BODY(ctxt, level) \
+{                             \
+	va_list args;             \
+	va_start (args, format);  \
+	usbi_log_v(ctxt, level, "", format, args); \
+	va_end(args);             \
 }
 }
-
-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
 #else
-	(void)ctx;
+#define LOG_BODY(ctxt, level) do { (void)(ctxt); } while(0)
 #endif
 #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_info(struct libusb_context *ctx, const char *format,
+	...)
+	LOG_BODY(ctx,LIBUSB_LOG_LEVEL_INFO)
+static inline void usbi_warn(struct libusb_context *ctx, const char *format,
+	...)
+	LOG_BODY(ctx,LIBUSB_LOG_LEVEL_WARNING)
+static inline void usbi_err( struct libusb_context *ctx, const char *format,
+	...)
+	LOG_BODY(ctx,LIBUSB_LOG_LEVEL_ERROR)
 
 
-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
-}
+static inline void usbi_dbg(const char *format, ...)
+	LOG_BODY(NULL,LIBUSB_LOG_LEVEL_DEBUG)
 
 
 #endif /* !defined(_MSC_VER) || _MSC_VER >= 1400 */
 #endif /* !defined(_MSC_VER) || _MSC_VER >= 1400 */
 
 
@@ -221,32 +210,13 @@ static inline void usbi_dbg(const char *fmt, ...)
 #define IS_XFERIN(xfer) (0 != ((xfer)->endpoint & LIBUSB_ENDPOINT_IN))
 #define IS_XFERIN(xfer) (0 != ((xfer)->endpoint & LIBUSB_ENDPOINT_IN))
 #define IS_XFEROUT(xfer) (!IS_XFERIN(xfer))
 #define IS_XFEROUT(xfer) (!IS_XFERIN(xfer))
 
 
-/* Internal abstractions for thread synchronization and poll */
+/* Internal abstraction for thread synchronization */
 #if defined(THREADS_POSIX)
 #if defined(THREADS_POSIX)
-#include <os/threads_posix.h>
-#elif defined(OS_WINDOWS)
+#include "os/threads_posix.h"
+#elif defined(OS_WINDOWS) || defined(OS_WINCE)
 #include <os/threads_windows.h>
 #include <os/threads_windows.h>
 #endif
 #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;
 extern struct libusb_context *usbi_default_context;
 
 
 struct libusb_context {
 struct libusb_context {
@@ -268,7 +238,7 @@ struct libusb_context {
 	/* A list of registered hotplug callbacks */
 	/* A list of registered hotplug callbacks */
 	struct list_head hotplug_cbs;
 	struct list_head hotplug_cbs;
 	usbi_mutex_t hotplug_cbs_lock;
 	usbi_mutex_t hotplug_cbs_lock;
-        int hotplug_pipe[2];
+	int hotplug_pipe[2];
 
 
 	/* this is a list of in-flight transfer handles, sorted by timeout
 	/* this is a list of in-flight transfer handles, sorted by timeout
 	 * expiration. URBs to timeout the soonest are placed at the beginning of
 	 * expiration. URBs to timeout the soonest are placed at the beginning of
@@ -308,7 +278,7 @@ struct libusb_context {
 	int timerfd;
 	int timerfd;
 #endif
 #endif
 
 
-        struct list_head list;
+	struct list_head list;
 };
 };
 
 
 #ifdef USBI_TIMERFD_AVAILABLE
 #ifdef USBI_TIMERFD_AVAILABLE
@@ -326,6 +296,8 @@ struct libusb_device {
 	struct libusb_context *ctx;
 	struct libusb_context *ctx;
 
 
 	uint8_t bus_number;
 	uint8_t bus_number;
+	uint8_t port_number;
+	struct libusb_device* parent_dev;
 	uint8_t device_address;
 	uint8_t device_address;
 	uint8_t num_configurations;
 	uint8_t num_configurations;
 	enum libusb_speed speed;
 	enum libusb_speed speed;
@@ -342,7 +314,7 @@ struct libusb_device {
 #else
 #else
 	[0] /* non-standard, but usually working code */
 	[0] /* non-standard, but usually working code */
 #endif
 #endif
-    ;
+	;
 };
 };
 
 
 struct libusb_device_handle {
 struct libusb_device_handle {
@@ -352,13 +324,14 @@ struct libusb_device_handle {
 
 
 	struct list_head list;
 	struct list_head list;
 	struct libusb_device *dev;
 	struct libusb_device *dev;
+	int auto_detach_kernel_driver;
 	unsigned char os_priv
 	unsigned char os_priv
 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
 	[] /* valid C99 code */
 	[] /* valid C99 code */
 #else
 #else
 	[0] /* non-standard, but usually working code */
 	[0] /* non-standard, but usually working code */
 #endif
 #endif
-    ;
+	;
 };
 };
 
 
 enum {
 enum {
@@ -409,7 +382,7 @@ enum usbi_transfer_flags {
 	/* Operation on the transfer failed because the device disappeared */
 	/* Operation on the transfer failed because the device disappeared */
 	USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3,
 	USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3,
 
 
-	/* Set by backend submit_transfer() if the fds in use were updated */
+	/* Set by backend submit_transfer() if the fds in use have been updated */
 	USBI_TRANSFER_UPDATED_FDS = 1 << 4,
 	USBI_TRANSFER_UPDATED_FDS = 1 << 4,
 };
 };
 
 
@@ -461,7 +434,26 @@ int usbi_get_config_index_by_value(struct libusb_device *dev,
 void usbi_connect_device (struct libusb_device *dev);
 void usbi_connect_device (struct libusb_device *dev);
 void usbi_disconnect_device (struct libusb_device *dev);
 void usbi_disconnect_device (struct libusb_device *dev);
 
 
-/* polling */
+/* Internal abstraction for poll (needs struct usbi_transfer on Windows) */
+#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) || defined(OS_NETBSD)
+#include <unistd.h>
+#include "os/poll_posix.h"
+#elif defined(OS_WINDOWS) || defined(OS_WINCE)
+#include "os/poll_windows.h"
+#endif
+
+#if (defined(OS_WINDOWS) || defined(OS_WINCE)) && !defined(__GNUC__)
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+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
 
 
 struct usbi_pollfd {
 struct usbi_pollfd {
 	/* must come first */
 	/* must come first */
@@ -490,7 +482,7 @@ struct discovered_devs {
 #else
 #else
 	[0] /* non-standard, but usually working code */
 	[0] /* non-standard, but usually working code */
 #endif
 #endif
-    ;
+	;
 };
 };
 
 
 struct discovered_devs *discovered_devs_append(
 struct discovered_devs *discovered_devs_append(
@@ -504,11 +496,14 @@ struct usbi_os_backend {
 	/* A human-readable name for your backend, e.g. "Linux usbfs" */
 	/* A human-readable name for your backend, e.g. "Linux usbfs" */
 	const char *name;
 	const char *name;
 
 
+	/* Binary mask for backend specific capabilities */
+	uint32_t caps;
+
 	/* Perform initialization of your backend. You might use this function
 	/* Perform initialization of your backend. You might use this function
 	 * to determine specific capabilities of the system, allocate required
 	 * to determine specific capabilities of the system, allocate required
 	 * data structures for later, etc.
 	 * data structures for later, etc.
 	 *
 	 *
-	 * This function is called when a libusb user initializes the library
+	 * This function is called when a libusbx user initializes the library
 	 * prior to use.
 	 * prior to use.
 	 *
 	 *
 	 * Return 0 on success, or a LIBUSB_ERROR code on failure.
 	 * Return 0 on success, or a LIBUSB_ERROR code on failure.
@@ -538,7 +533,7 @@ struct usbi_os_backend {
 	 * but that is an unlikely case.
 	 * but that is an unlikely case.
 	 *
 	 *
 	 * After computing a session ID for a device, call
 	 * After computing a session ID for a device, call
-	 * usbi_get_device_by_session_id(). This function checks if libusb already
+	 * usbi_get_device_by_session_id(). This function checks if libusbx already
 	 * knows about the device, and if so, it provides you with a libusb_device
 	 * knows about the device, and if so, it provides you with a libusb_device
 	 * structure for it.
 	 * structure for it.
 	 *
 	 *
@@ -569,18 +564,37 @@ struct usbi_os_backend {
 	 * This function is executed when the user wishes to retrieve a list
 	 * This function is executed when the user wishes to retrieve a list
 	 * of USB devices connected to the system.
 	 * of USB devices connected to the system.
 	 *
 	 *
+	 * If the backend has hotplug support, this function is not used!
+	 *
 	 * Return 0 on success, or a LIBUSB_ERROR code on failure.
 	 * Return 0 on success, or a LIBUSB_ERROR code on failure.
 	 */
 	 */
 	int (*get_device_list)(struct libusb_context *ctx,
 	int (*get_device_list)(struct libusb_context *ctx,
 		struct discovered_devs **discdevs);
 		struct discovered_devs **discdevs);
 
 
+	/* Apps which were written before hotplug support, may listen for
+	 * hotplug events on their own and call libusb_get_device_list on
+	 * device addition. In this case libusb_get_device_list will likely
+	 * return a list without the new device in there, as the hotplug
+	 * event thread will still be busy enumerating the device, which may
+	 * take a while, or may not even have seen the event yet.
+	 *
+	 * To avoid this libusb_get_device_list will call this optional
+	 * function for backends with hotplug support before copying
+	 * ctx->usb_devs to the user. In this function the backend should
+	 * ensure any pending hotplug events are fully processed before
+	 * returning.
+	 *
+	 * Optional, should be implemented by backends with hotplug support.
+	 */
+	void (*hotplug_poll)(void);
+
 	/* Open a device for I/O and other USB operations. The device handle
 	/* Open a device for I/O and other USB operations. The device handle
 	 * is preallocated for you, you can retrieve the device in question
 	 * is preallocated for you, you can retrieve the device in question
 	 * through handle->dev.
 	 * through handle->dev.
 	 *
 	 *
 	 * Your backend should allocate any internal resources required for I/O
 	 * Your backend should allocate any internal resources required for I/O
 	 * and other operations so that those operations can happen (hopefully)
 	 * and other operations so that those operations can happen (hopefully)
-	 * without hiccup. This is also a good place to inform libusb that it
+	 * without hiccup. This is also a good place to inform libusbx that it
 	 * should monitor certain file descriptors related to this device -
 	 * should monitor certain file descriptors related to this device -
 	 * see the usbi_add_pollfd() function.
 	 * see the usbi_add_pollfd() function.
 	 *
 	 *
@@ -604,7 +618,7 @@ struct usbi_os_backend {
 	/* Close a device such that the handle cannot be used again. Your backend
 	/* Close a device such that the handle cannot be used again. Your backend
 	 * should destroy any resources that were allocated in the open path.
 	 * 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
 	 * 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
+	 * libusbx of any file descriptors associated with this device that should
 	 * no longer be monitored.
 	 * no longer be monitored.
 	 *
 	 *
 	 * This function is called when the user closes a device handle.
 	 * This function is called when the user closes a device handle.
@@ -683,13 +697,29 @@ struct usbi_os_backend {
 		uint8_t config_index, unsigned char *buffer, size_t len,
 		uint8_t config_index, unsigned char *buffer, size_t len,
 		int *host_endian);
 		int *host_endian);
 
 
+	/* Like get_config_descriptor but then by bConfigurationValue instead
+	 * of by index.
+	 *
+	 * Optional, if not present the core will call get_config_descriptor
+	 * for all configs until it finds the desired bConfigurationValue.
+	 *
+	 * Returns a pointer to the raw-descriptor in *buffer, this memory
+	 * is valid as long as device is valid.
+	 *
+	 * Returns the length of the returned raw-descriptor on success,
+	 * or a LIBUSB_ERROR code on failure.
+	 */
+	int (*get_config_descriptor_by_value)(struct libusb_device *device,
+		uint8_t bConfigurationValue, unsigned char **buffer,
+		int *host_endian);
+
 	/* Get the bConfigurationValue for the active configuration for a device.
 	/* Get the bConfigurationValue for the active configuration for a device.
 	 * Optional. This should only be implemented if you can retrieve it from
 	 * Optional. This should only be implemented if you can retrieve it from
 	 * cache (don't generate I/O).
 	 * cache (don't generate I/O).
 	 *
 	 *
 	 * If you cannot retrieve this from cache, either do not implement this
 	 * If you cannot retrieve this from cache, either do not implement this
 	 * function, or return LIBUSB_ERROR_NOT_SUPPORTED. This will cause
 	 * function, or return LIBUSB_ERROR_NOT_SUPPORTED. This will cause
-	 * libusb to retrieve the information through a standard control transfer.
+	 * libusbx to retrieve the information through a standard control transfer.
 	 *
 	 *
 	 * This function must be non-blocking.
 	 * This function must be non-blocking.
 	 * Return:
 	 * Return:
@@ -866,6 +896,8 @@ struct usbi_os_backend {
 	 *
 	 *
 	 * This function must not block.
 	 * This function must not block.
 	 *
 	 *
+	 * This function gets called with the flying_transfers_lock locked!
+	 *
 	 * Return:
 	 * Return:
 	 * - 0 on success
 	 * - 0 on success
 	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
 	 * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
@@ -886,7 +918,7 @@ struct usbi_os_backend {
 	 * all private data from the transfer as if you were just about to report
 	 * all private data from the transfer as if you were just about to report
 	 * completion or cancellation.
 	 * completion or cancellation.
 	 *
 	 *
-	 * This function might seem a bit out of place. It is used when libusb
+	 * This function might seem a bit out of place. It is used when libusbx
 	 * detects a disconnected device - it calls this function for all pending
 	 * detects a disconnected device - it calls this function for all pending
 	 * transfers before reporting completion (with the disconnect code) to
 	 * transfers before reporting completion (with the disconnect code) to
 	 * the user. Maybe we can improve upon this internal interface in future.
 	 * the user. Maybe we can improve upon this internal interface in future.
@@ -965,10 +997,11 @@ extern const struct usbi_os_backend * const usbi_backend;
 extern const struct usbi_os_backend linux_usbfs_backend;
 extern const struct usbi_os_backend linux_usbfs_backend;
 extern const struct usbi_os_backend darwin_backend;
 extern const struct usbi_os_backend darwin_backend;
 extern const struct usbi_os_backend openbsd_backend;
 extern const struct usbi_os_backend openbsd_backend;
+extern const struct usbi_os_backend netbsd_backend;
 extern const struct usbi_os_backend windows_backend;
 extern const struct usbi_os_backend windows_backend;
+extern const struct usbi_os_backend wince_backend;
 
 
 extern struct list_head active_contexts_list;
 extern struct list_head active_contexts_list;
 extern usbi_mutex_static_t active_contexts_lock;
 extern usbi_mutex_static_t active_contexts_lock;
 
 
 #endif
 #endif
-

File diff suppressed because it is too large
+ 317 - 198
compat/libusb-1.0/libusb/os/darwin_usb.c


+ 28 - 41
compat/libusb-1.0/libusb/os/darwin_usb.h

@@ -1,6 +1,6 @@
 /*
 /*
- * darwin backend for libusb 1.0
- * Copyright (C) 2008-2013 Nathan Hjelm <hjelmn@users.sourceforge.net>
+ * darwin backend for libusbx 1.0
+ * Copyright © 2008-2013 Nathan Hjelm <hjelmn@users.sourceforge.net>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -28,7 +28,19 @@
 #include <IOKit/IOCFPlugIn.h>
 #include <IOKit/IOCFPlugIn.h>
 
 
 /* IOUSBInterfaceInferface */
 /* IOUSBInterfaceInferface */
-#if defined (kIOUSBInterfaceInterfaceID300)
+#if defined (kIOUSBInterfaceInterfaceID550)
+
+#define usb_interface_t IOUSBInterfaceInterface550
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID550
+#define InterfaceVersion 550
+
+#elif defined (kIOUSBInterfaceInterfaceID500)
+
+#define usb_interface_t IOUSBInterfaceInterface500
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID500
+#define InterfaceVersion 500
+
+#elif defined (kIOUSBInterfaceInterfaceID300)
 
 
 #define usb_interface_t IOUSBInterfaceInterface300
 #define usb_interface_t IOUSBInterfaceInterface300
 #define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300
 #define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300
@@ -46,24 +58,6 @@
 #define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
 #define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
 #define InterfaceVersion 220
 #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
 #else
 
 
 #error "IOUSBFamily is too old. Please upgrade your OS"
 #error "IOUSBFamily is too old. Please upgrade your OS"
@@ -95,24 +89,11 @@
 #define DeviceInterfaceID kIOUSBDeviceInterfaceID245
 #define DeviceInterfaceID kIOUSBDeviceInterfaceID245
 #define DeviceVersion 245
 #define DeviceVersion 245
 
 
-#elif defined (kIOUSBDeviceInterfaceID197)
-
+#elif defined (kIOUSBDeviceInterfaceID220)
 #define usb_device_t    IOUSBDeviceInterface197
 #define usb_device_t    IOUSBDeviceInterface197
 #define DeviceInterfaceID kIOUSBDeviceInterfaceID197
 #define DeviceInterfaceID kIOUSBDeviceInterfaceID197
 #define DeviceVersion 197
 #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
 #else
 
 
 #error "IOUSBFamily is too old. Please upgrade your OS"
 #error "IOUSBFamily is too old. Please upgrade your OS"
@@ -127,13 +108,23 @@ typedef IOCFPlugInInterface *io_cf_plugin_ref_t;
 typedef IONotificationPortRef io_notification_port_t;
 typedef IONotificationPortRef io_notification_port_t;
 
 
 /* private structures */
 /* private structures */
-struct darwin_device_priv {
+struct darwin_cached_device {
+  struct list_head      list;
   IOUSBDeviceDescriptor dev_descriptor;
   IOUSBDeviceDescriptor dev_descriptor;
   UInt32                location;
   UInt32                location;
+  UInt64                parent_session;
+  UInt64                session;
+  UInt16                address;
   char                  sys_path[21];
   char                  sys_path[21];
   usb_device_t        **device;
   usb_device_t        **device;
   int                   open_count;
   int                   open_count;
-  UInt8                 first_config, active_config;
+  UInt8                 first_config, active_config, port;  
+  int                   can_enumerate;
+  int                   refcount;
+};
+
+struct darwin_device_priv {
+  struct darwin_cached_device *dev;
 };
 };
 
 
 struct darwin_device_handle_priv {
 struct darwin_device_handle_priv {
@@ -156,11 +147,7 @@ struct darwin_transfer_priv {
   int num_iso_packets;
   int num_iso_packets;
 
 
   /* Control */
   /* Control */
-#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
   IOUSBDevRequestTO req;
   IOUSBDevRequestTO req;
-#else
-  IOUSBDevRequest req;
-#endif
 
 
   /* Bulk */
   /* Bulk */
 };
 };

+ 156 - 42
compat/libusb-1.0/libusb/os/linux_netlink.c

@@ -21,6 +21,10 @@
  */
  */
 
 
 #include "config.h"
 #include "config.h"
+#include "libusb.h"
+#include "libusbi.h"
+#include "linux_usbfs.h"
+
 #include <ctype.h>
 #include <ctype.h>
 #include <dirent.h>
 #include <dirent.h>
 #include <errno.h>
 #include <errno.h>
@@ -30,46 +34,113 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/types.h>
+
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #include <sys/socket.h>
-#include <arpa/inet.h>
+#endif
 
 
-#include "libusb.h"
-#include "libusbi.h"
-#include "linux_usbfs.h"
+#include <arpa/inet.h>
 
 
+#ifdef HAVE_LINUX_NETLINK_H
 #include <linux/netlink.h>
 #include <linux/netlink.h>
+#endif
+
+#ifdef HAVE_LINUX_FILTER_H
 #include <linux/filter.h>
 #include <linux/filter.h>
+#endif
 
 
 #define KERNEL 1
 #define KERNEL 1
 
 
 static int linux_netlink_socket = -1;
 static int linux_netlink_socket = -1;
+static int netlink_control_pipe[2] = { -1, -1 };
 static pthread_t libusb_linux_event_thread;
 static pthread_t libusb_linux_event_thread;
 
 
 static void *linux_netlink_event_thread_main(void *arg);
 static void *linux_netlink_event_thread_main(void *arg);
 
 
 struct sockaddr_nl snl = { .nl_family=AF_NETLINK, .nl_groups=KERNEL };
 struct sockaddr_nl snl = { .nl_family=AF_NETLINK, .nl_groups=KERNEL };
 
 
+static int set_fd_cloexec_nb (int fd)
+{
+	int flags;
+
+#if defined(FD_CLOEXEC)
+	flags = fcntl (linux_netlink_socket, F_GETFD);
+	if (0 > flags) {
+		return -1;
+	}
+
+	if (!(flags & FD_CLOEXEC)) {
+		fcntl (linux_netlink_socket, F_SETFD, flags | FD_CLOEXEC);
+	}
+#endif
+
+	flags = fcntl (linux_netlink_socket, F_GETFL);
+	if (0 > flags) {
+		return -1;
+	}
+
+	if (!(flags & O_NONBLOCK)) {
+		fcntl (linux_netlink_socket, F_SETFL, flags | O_NONBLOCK);
+	}
+
+	return 0;
+}
+
 int linux_netlink_start_event_monitor(void)
 int linux_netlink_start_event_monitor(void)
 {
 {
+	int socktype = SOCK_RAW;
 	int ret;
 	int ret;
 
 
 	snl.nl_groups = KERNEL;
 	snl.nl_groups = KERNEL;
 
 
-	linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
+#if defined(SOCK_CLOEXEC)
+	socktype |= SOCK_CLOEXEC;
+#endif
+#if defined(SOCK_NONBLOCK)
+	socktype |= SOCK_NONBLOCK;
+#endif
+
+	linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
+	if (-1 == linux_netlink_socket && EINVAL == errno) {
+		linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
+	}
+
 	if (-1 == linux_netlink_socket) {
 	if (-1 == linux_netlink_socket) {
 		return LIBUSB_ERROR_OTHER;
 		return LIBUSB_ERROR_OTHER;
 	}
 	}
 
 
+	ret = set_fd_cloexec_nb (linux_netlink_socket);
+	if (0 != ret) {
+		close (linux_netlink_socket);
+		linux_netlink_socket = -1;
+		return LIBUSB_ERROR_OTHER;
+	}
+
 	ret = bind(linux_netlink_socket, (struct sockaddr *) &snl, sizeof(snl));
 	ret = bind(linux_netlink_socket, (struct sockaddr *) &snl, sizeof(snl));
 	if (0 != ret) {
 	if (0 != ret) {
+	        close(linux_netlink_socket);
 		return LIBUSB_ERROR_OTHER;
 		return LIBUSB_ERROR_OTHER;
 	}
 	}
 
 
 	/* TODO -- add authentication */
 	/* TODO -- add authentication */
 	/* setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); */
 	/* setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); */
 
 
+	ret = usbi_pipe(netlink_control_pipe);
+	if (ret) {
+		usbi_err(NULL, "could not create netlink control pipe");
+	        close(linux_netlink_socket);
+		return LIBUSB_ERROR_OTHER;
+	}
+
 	ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL);
 	ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL);
 	if (0 != ret) {
 	if (0 != ret) {
+        	close(netlink_control_pipe[0]);
+        	close(netlink_control_pipe[1]);
+	        close(linux_netlink_socket);
 		return LIBUSB_ERROR_OTHER;
 		return LIBUSB_ERROR_OTHER;
 	}
 	}
 
 
@@ -79,22 +150,30 @@ int linux_netlink_start_event_monitor(void)
 int linux_netlink_stop_event_monitor(void)
 int linux_netlink_stop_event_monitor(void)
 {
 {
 	int r;
 	int r;
+	char dummy = 1;
 
 
 	if (-1 == linux_netlink_socket) {
 	if (-1 == linux_netlink_socket) {
 		/* already closed. nothing to do */
 		/* already closed. nothing to do */
 		return LIBUSB_SUCCESS;
 		return LIBUSB_SUCCESS;
 	}
 	}
 
 
-	r = close(linux_netlink_socket);
-	if (0 > r) {
-		usbi_err(NULL, "error closing netlink socket. %s", strerror(errno));
-		return LIBUSB_ERROR_OTHER;
+	/* Write some dummy data to the control pipe and
+	 * wait for the thread to exit */
+	r = usbi_write(netlink_control_pipe[1], &dummy, sizeof(dummy));
+	if (r <= 0) {
+		usbi_warn(NULL, "netlink control pipe signal failed");
 	}
 	}
+	pthread_join(libusb_linux_event_thread, NULL);
 
 
-	pthread_cancel(libusb_linux_event_thread);
-
+	close(linux_netlink_socket);
 	linux_netlink_socket = -1;
 	linux_netlink_socket = -1;
 
 
+	/* close and reset control pipe */
+	close(netlink_control_pipe[0]);
+	close(netlink_control_pipe[1]);
+	netlink_control_pipe[0] = -1;
+	netlink_control_pipe[1] = -1;
+
 	return LIBUSB_SUCCESS;
 	return LIBUSB_SUCCESS;
 }
 }
 
 
@@ -127,10 +206,12 @@ static int linux_netlink_parse(char *buffer, size_t len, int *detached, const ch
 	*devaddr  = 0;
 	*devaddr  = 0;
 
 
 	tmp = netlink_message_parse((const char *) buffer, len, "ACTION");
 	tmp = netlink_message_parse((const char *) buffer, len, "ACTION");
+	if (tmp == NULL)
+		return -1;
 	if (0 == strcmp(tmp, "remove")) {
 	if (0 == strcmp(tmp, "remove")) {
 		*detached = 1;
 		*detached = 1;
 	} else if (0 != strcmp(tmp, "add")) {
 	} else if (0 != strcmp(tmp, "add")) {
-		usbi_dbg("unknown device action");
+		usbi_dbg("unknown device action %s", tmp);
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -180,52 +261,85 @@ static int linux_netlink_parse(char *buffer, size_t len, int *detached, const ch
 	return 0;
 	return 0;
 }
 }
 
 
-static void *linux_netlink_event_thread_main(void *arg)
+static int linux_netlink_read_message(void)
 {
 {
-	struct pollfd fds = {.fd = linux_netlink_socket,
-			     .events = POLLIN};
 	unsigned char buffer[1024];
 	unsigned char buffer[1024];
 	struct iovec iov = {.iov_base = buffer, .iov_len = sizeof(buffer)};
 	struct iovec iov = {.iov_base = buffer, .iov_len = sizeof(buffer)};
 	struct msghdr meh = { .msg_iov=&iov, .msg_iovlen=1,
 	struct msghdr meh = { .msg_iov=&iov, .msg_iovlen=1,
 			     .msg_name=&snl, .msg_namelen=sizeof(snl) };
 			     .msg_name=&snl, .msg_namelen=sizeof(snl) };
+	const char *sys_name = NULL;
 	uint8_t busnum, devaddr;
 	uint8_t busnum, devaddr;
 	int detached, r;
 	int detached, r;
 	size_t len;
 	size_t len;
 
 
-	/* silence compiler warning */
-	(void) arg;
+	/* read netlink message */
+	memset(buffer, 0, sizeof(buffer));
+	len = recvmsg(linux_netlink_socket, &meh, 0);
+	if (len < 32) {
+		if (errno != EAGAIN)
+			usbi_dbg("error recieving message from netlink");
+		return -1;
+	}
 
 
-	while (1 == poll(&fds, 1, -1)) {
-		const char *sys_name = NULL;
+	/* TODO -- authenticate this message is from the kernel or udevd */
 
 
-		if (POLLIN != fds.revents) {
-			break;
-		}
+	r = linux_netlink_parse(buffer, len, &detached, &sys_name,
+				&busnum, &devaddr);
+	if (r)
+		return r;
 
 
-		/* read netlink message */
-		memset(buffer, 0, sizeof(buffer));
-		len = recvmsg(linux_netlink_socket, &meh, 0);
-		if (len < 32) {
-			usbi_dbg("error recieving message from netlink");
-			continue;
-		}
+	usbi_dbg("netlink hotplug found device busnum: %hhu, devaddr: %hhu, sys_name: %s, removed: %s",
+		 busnum, devaddr, sys_name, detached ? "yes" : "no");
 
 
-		/* TODO -- authenticate this message is from the kernel or udevd */
+	/* signal device is available (or not) to all contexts */
+	if (detached)
+		linux_device_disconnected(busnum, devaddr, sys_name);
+	else
+		linux_hotplug_enumerate(busnum, devaddr, sys_name);
 
 
-		r = linux_netlink_parse(buffer, len, &detached, &sys_name,
-					&busnum, &devaddr);
-		if (r)
-			continue;
+	return 0;
+}
 
 
-		usbi_dbg("netlink hotplug found device busnum: %hhu, devaddr: %hhu, sys_name: %s, removed: %s",
-			 busnum, devaddr, sys_name, detached ? "yes" : "no");
+static void *linux_netlink_event_thread_main(void *arg)
+{
+	char dummy;
+	int r;
+	struct pollfd fds[] = {
+		{ .fd = netlink_control_pipe[0],
+		  .events = POLLIN },
+		{ .fd = linux_netlink_socket,
+		  .events = POLLIN },
+	};
 
 
-		/* signal device is available (or not) to all contexts */
-		if (detached)
-			linux_hotplug_disconnected(busnum, devaddr, sys_name);
-		else
-			linux_hotplug_enumerate(busnum, devaddr, sys_name);
+	/* silence compiler warning */
+	(void) arg;
+
+	while (poll(fds, 2, -1) >= 0) {
+		if (fds[0].revents & POLLIN) {
+			/* activity on control pipe, read the byte and exit */
+			r = usbi_read(netlink_control_pipe[0], &dummy, sizeof(dummy));
+			if (r <= 0) {
+				usbi_warn(NULL, "netlink control pipe read failed");
+			}
+			break;
+		}
+		if (fds[1].revents & POLLIN) {
+        		usbi_mutex_static_lock(&linux_hotplug_lock);
+	        	linux_netlink_read_message();
+	        	usbi_mutex_static_unlock(&linux_hotplug_lock);
+		}
 	}
 	}
 
 
-	return NULL;	
+	return NULL;
+}
+
+void linux_netlink_hotplug_poll(void)
+{
+	int r;
+
+	usbi_mutex_static_lock(&linux_hotplug_lock);
+	do {
+		r = linux_netlink_read_message();
+	} while (r == 0);
+	usbi_mutex_static_unlock(&linux_hotplug_lock);
 }
 }

+ 127 - 63
compat/libusb-1.0/libusb/os/linux_udev.c

@@ -20,7 +20,9 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
  */
 
 
-#include <config.h>
+#include "config.h"
+
+#include <assert.h>
 #include <ctype.h>
 #include <ctype.h>
 #include <dirent.h>
 #include <dirent.h>
 #include <errno.h>
 #include <errno.h>
@@ -44,84 +46,148 @@
 /* udev context */
 /* udev context */
 static struct udev *udev_ctx = NULL;
 static struct udev *udev_ctx = NULL;
 static int udev_monitor_fd = -1;
 static int udev_monitor_fd = -1;
+static int udev_control_pipe[2] = {-1, -1};
 static struct udev_monitor *udev_monitor = NULL;
 static struct udev_monitor *udev_monitor = NULL;
 static pthread_t linux_event_thread;
 static pthread_t linux_event_thread;
 
 
-static void udev_hotplug_event(void);
+static void udev_hotplug_event(struct udev_device* udev_dev);
 static void *linux_udev_event_thread_main(void *arg);
 static void *linux_udev_event_thread_main(void *arg);
 
 
 int linux_udev_start_event_monitor(void)
 int linux_udev_start_event_monitor(void)
 {
 {
 	int r;
 	int r;
 
 
-	if (NULL == udev_ctx) {
-		udev_ctx = udev_new();
-		if (!udev_ctx) {
-			return LIBUSB_ERROR_OTHER;
-		}
+	assert(udev_ctx == NULL);
+	udev_ctx = udev_new();
+	if (!udev_ctx) {
+		usbi_err(NULL, "could not create udev context");
+		return LIBUSB_ERROR_OTHER;
+	}
+
+	udev_monitor = udev_monitor_new_from_netlink(udev_ctx, "udev");
+	if (!udev_monitor) {
+		usbi_err(NULL, "could not initialize udev monitor");
+		goto err_free_ctx;
 	}
 	}
 
 
-        udev_monitor = udev_monitor_new_from_netlink(udev_ctx, "udev");
-        if (!udev_monitor) {
-                usbi_err(NULL, "could not initialize udev monitor");
-                return LIBUSB_ERROR_OTHER;
-        }
+	r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", 0);
+	if (r) {
+		usbi_err(NULL, "could not initialize udev monitor filter for \"usb\" subsystem");
+		goto err_free_monitor;
+	}
+
+	if (udev_monitor_enable_receiving(udev_monitor)) {
+		usbi_err(NULL, "failed to enable the udev monitor");
+		goto err_free_monitor;
+	}
 
 
-        r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", 0);
-        if (r) {
-                usbi_err(NULL, "could not initialize udev monitor filter for \"usb\" subsystem");
-                return LIBUSB_ERROR_OTHER;
-        }
+	udev_monitor_fd = udev_monitor_get_fd(udev_monitor);
+
+	/* Some older versions of udev are not non-blocking by default,
+	 * so make sure this is set */
+	r = fcntl(udev_monitor_fd, F_GETFL);
+	if (r == -1) {
+		usbi_err(NULL, "getting udev monitor fd flags (%d)", errno);
+		goto err_free_monitor;
+	}
+	r = fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK);
+	if (r) {
+		usbi_err(NULL, "setting udev monitor fd flags (%d)", errno);
+		goto err_free_monitor;
+	}
 
 
-        if (udev_monitor_enable_receiving(udev_monitor)) {
-                usbi_err(NULL, "failed to enable the udev monitor");
-                return LIBUSB_ERROR_OTHER;
-        }
+	r = usbi_pipe(udev_control_pipe);
+	if (r) {
+		usbi_err(NULL, "could not create udev control pipe");
+		goto err_free_monitor;
+	}
 
 
-        udev_monitor_fd = udev_monitor_get_fd(udev_monitor);
+	r = pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL);
+	if (r) {
+		usbi_err(NULL, "creating hotplug event thread (%d)", r);
+		goto err_close_pipe;
+	}
 
 
-        pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL);
+	return LIBUSB_SUCCESS;
 
 
-        return LIBUSB_SUCCESS;
+err_close_pipe:
+	close(udev_control_pipe[0]);
+	close(udev_control_pipe[1]);
+err_free_monitor:
+	udev_monitor_unref(udev_monitor);
+	udev_monitor = NULL;
+	udev_monitor_fd = -1;
+err_free_ctx:
+	udev_unref(udev_ctx);
+	udev_ctx = NULL;
+	return LIBUSB_ERROR_OTHER;
 }
 }
 
 
 int linux_udev_stop_event_monitor(void)
 int linux_udev_stop_event_monitor(void)
 {
 {
-        if (-1 == udev_monitor_fd) {
-                /* this should never happen */
-                return LIBUSB_ERROR_OTHER;
-        }
+	char dummy = 1;
+	int r;
 
 
-	/* Cancel the event thread. This is the only way to garauntee the thread
-	   exits since closing the monitor fd won't necessarily cause poll
-	   to return. */
-	pthread_cancel(linux_event_thread);
+	assert(udev_ctx != NULL);
+	assert(udev_monitor != NULL);
+	assert(udev_monitor_fd != -1);
+
+	/* Write some dummy data to the control pipe and
+	 * wait for the thread to exit */
+	r = usbi_write(udev_control_pipe[1], &dummy, sizeof(dummy));
+	if (r <= 0) {
+		usbi_warn(NULL, "udev control pipe signal failed");
+	}
+	pthread_join(linux_event_thread, NULL);
 
 
 	/* Release the udev monitor */
 	/* Release the udev monitor */
-        udev_monitor_unref(udev_monitor);
+	udev_monitor_unref(udev_monitor);
 	udev_monitor = NULL;
 	udev_monitor = NULL;
-        udev_monitor_fd = -1;
+	udev_monitor_fd = -1;
 
 
 	/* Clean up the udev context */
 	/* Clean up the udev context */
 	udev_unref(udev_ctx);
 	udev_unref(udev_ctx);
 	udev_ctx = NULL;
 	udev_ctx = NULL;
 
 
-        return LIBUSB_SUCCESS;
+	/* close and reset control pipe */
+	close(udev_control_pipe[0]);
+	close(udev_control_pipe[1]);
+	udev_control_pipe[0] = -1;
+	udev_control_pipe[1] = -1;
+
+	return LIBUSB_SUCCESS;
 }
 }
 
 
-static void *linux_udev_event_thread_main(void __attribute__((unused)) *arg)
+static void *linux_udev_event_thread_main(void *arg)
 {
 {
-	struct pollfd fds = {.fd = udev_monitor_fd,
-			     .events = POLLIN};
+	char dummy;
+	int r;
+	struct udev_device* udev_dev;
+	struct pollfd fds[] = {
+		{.fd = udev_control_pipe[0],
+		 .events = POLLIN},
+		{.fd = udev_monitor_fd,
+		 .events = POLLIN},
+	};
 
 
 	usbi_dbg("udev event thread entering.");
 	usbi_dbg("udev event thread entering.");
 
 
-	while (1 == poll(&fds, 1, -1)) {
-		if (NULL == udev_monitor || POLLIN != fds.revents) {
+	while (poll(fds, 2, -1) >= 0) {
+		if (fds[0].revents & POLLIN) {
+			/* activity on control pipe, read the byte and exit */
+			r = usbi_read(udev_control_pipe[0], &dummy, sizeof(dummy));
+			if (r <= 0) {
+				usbi_warn(NULL, "udev control pipe read failed");
+			}
 			break;
 			break;
 		}
 		}
-
-		udev_hotplug_event();
+		if (fds[1].revents & POLLIN) {
+			usbi_mutex_static_lock(&linux_hotplug_lock);
+			udev_dev = udev_monitor_receive_device(udev_monitor);
+			if (udev_dev)
+				udev_hotplug_event(udev_dev);
+			usbi_mutex_static_unlock(&linux_hotplug_lock);
+		}
 	}
 	}
 
 
 	usbi_dbg("udev event thread exiting");
 	usbi_dbg("udev event thread exiting");
@@ -144,30 +210,19 @@ static int udev_device_info(struct libusb_context *ctx, int detached,
 		return LIBUSB_ERROR_OTHER;
 		return LIBUSB_ERROR_OTHER;
 	}
 	}
 
 
-        return linux_get_device_address(ctx, detached, busnum, devaddr,
+	return linux_get_device_address(ctx, detached, busnum, devaddr,
 					dev_node, *sys_name);
 					dev_node, *sys_name);
 }
 }
 
 
-static void udev_hotplug_event(void)
+static void udev_hotplug_event(struct udev_device* udev_dev)
 {
 {
-	struct udev_device* udev_dev;
 	const char* udev_action;
 	const char* udev_action;
 	const char* sys_name = NULL;
 	const char* sys_name = NULL;
 	uint8_t busnum = 0, devaddr = 0;
 	uint8_t busnum = 0, devaddr = 0;
 	int detached;
 	int detached;
 	int r;
 	int r;
 
 
-	if (NULL == udev_monitor) {
-		return;
-	}
-
 	do {
 	do {
-		udev_dev = udev_monitor_receive_device(udev_monitor);
-		if (!udev_dev) {
-			usbi_err(NULL, "failed to read data from udev monitor socket.");
-			return;
-		}
-
 		udev_action = udev_device_get_action(udev_dev);
 		udev_action = udev_device_get_action(udev_dev);
 		if (!udev_action) {
 		if (!udev_action) {
 			break;
 			break;
@@ -185,7 +240,7 @@ static void udev_hotplug_event(void)
 		if (strncmp(udev_action, "add", 3) == 0) {
 		if (strncmp(udev_action, "add", 3) == 0) {
 			linux_hotplug_enumerate(busnum, devaddr, sys_name);
 			linux_hotplug_enumerate(busnum, devaddr, sys_name);
 		} else if (detached) {
 		} else if (detached) {
-			linux_hotplug_disconnected(busnum, devaddr, sys_name);
+			linux_device_disconnected(busnum, devaddr, sys_name);
 		} else {
 		} else {
 			usbi_err(NULL, "ignoring udev action %s", udev_action);
 			usbi_err(NULL, "ignoring udev action %s", udev_action);
 		}
 		}
@@ -202,12 +257,7 @@ int linux_udev_scan_devices(struct libusb_context *ctx)
 	const char *sys_name;
 	const char *sys_name;
 	int r;
 	int r;
 
 
-	if (NULL == udev_ctx) {
-		udev_ctx = udev_new();
-		if (!udev_ctx) {
-			return LIBUSB_ERROR_OTHER;
-		}
-	}
+	assert(udev_ctx != NULL);
 
 
 	enumerator = udev_enumerate_new(udev_ctx);
 	enumerator = udev_enumerate_new(udev_ctx);
 	if (NULL == enumerator) {
 	if (NULL == enumerator) {
@@ -237,6 +287,20 @@ int linux_udev_scan_devices(struct libusb_context *ctx)
 
 
 	udev_enumerate_unref(enumerator);
 	udev_enumerate_unref(enumerator);
 
 
-        return LIBUSB_SUCCESS;
+	return LIBUSB_SUCCESS;
 }
 }
 
 
+void linux_udev_hotplug_poll(void)
+{
+	struct udev_device* udev_dev;
+
+	usbi_mutex_static_lock(&linux_hotplug_lock);
+	do {
+		udev_dev = udev_monitor_receive_device(udev_monitor);
+		if (udev_dev) {
+			usbi_dbg("Handling hotplug event from hotplug_poll");
+			udev_hotplug_event(udev_dev);
+		}
+	} while (udev_dev);
+	usbi_mutex_static_unlock(&linux_hotplug_lock);
+}

File diff suppressed because it is too large
+ 429 - 500
compat/libusb-1.0/libusb/os/linux_usbfs.c


+ 20 - 7
compat/libusb-1.0/libusb/os/linux_usbfs.h

@@ -1,7 +1,7 @@
 /*
 /*
  * usbfs header structures
  * usbfs header structures
- * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
- * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ * Copyright © 2007 Daniel Drake <dsd@gentoo.org>
+ * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -123,6 +123,15 @@ struct usbfs_hub_portinfo {
 #define USBFS_CAP_NO_PACKET_SIZE_LIM	0x04
 #define USBFS_CAP_NO_PACKET_SIZE_LIM	0x04
 #define USBFS_CAP_BULK_SCATTER_GATHER	0x08
 #define USBFS_CAP_BULK_SCATTER_GATHER	0x08
 
 
+#define USBFS_DISCONNECT_CLAIM_IF_DRIVER	0x01
+#define USBFS_DISCONNECT_CLAIM_EXCEPT_DRIVER	0x02
+
+struct usbfs_disconnect_claim {
+	unsigned int interface;
+	unsigned int flags;
+	char driver[USBFS_MAXDRIVERNAME + 1];
+};
+
 #define IOCTL_USBFS_CONTROL	_IOWR('U', 0, struct usbfs_ctrltransfer)
 #define IOCTL_USBFS_CONTROL	_IOWR('U', 0, struct usbfs_ctrltransfer)
 #define IOCTL_USBFS_BULK		_IOWR('U', 2, struct usbfs_bulktransfer)
 #define IOCTL_USBFS_BULK		_IOWR('U', 2, struct usbfs_bulktransfer)
 #define IOCTL_USBFS_RESETEP	_IOR('U', 3, unsigned int)
 #define IOCTL_USBFS_RESETEP	_IOR('U', 3, unsigned int)
@@ -145,24 +154,28 @@ struct usbfs_hub_portinfo {
 #define IOCTL_USBFS_CLAIM_PORT	_IOR('U', 24, unsigned int)
 #define IOCTL_USBFS_CLAIM_PORT	_IOR('U', 24, unsigned int)
 #define IOCTL_USBFS_RELEASE_PORT	_IOR('U', 25, unsigned int)
 #define IOCTL_USBFS_RELEASE_PORT	_IOR('U', 25, unsigned int)
 #define IOCTL_USBFS_GET_CAPABILITIES	_IOR('U', 26, __u32)
 #define IOCTL_USBFS_GET_CAPABILITIES	_IOR('U', 26, __u32)
+#define IOCTL_USBFS_DISCONNECT_CLAIM	_IOR('U', 27, struct usbfs_disconnect_claim)
+
+extern usbi_mutex_static_t linux_hotplug_lock;
 
 
 #if defined(HAVE_LIBUDEV)
 #if defined(HAVE_LIBUDEV)
 int linux_udev_start_event_monitor(void);
 int linux_udev_start_event_monitor(void);
 int linux_udev_stop_event_monitor(void);
 int linux_udev_stop_event_monitor(void);
 int linux_udev_scan_devices(struct libusb_context *ctx);
 int linux_udev_scan_devices(struct libusb_context *ctx);
+void linux_udev_hotplug_poll(void);
 #else
 #else
 int linux_netlink_start_event_monitor(void);
 int linux_netlink_start_event_monitor(void);
 int linux_netlink_stop_event_monitor(void);
 int linux_netlink_stop_event_monitor(void);
+void linux_netlink_hotplug_poll(void);
 #endif
 #endif
 
 
 void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name);
 void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name);
-void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name);
+void linux_device_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name);
 
 
 int linux_get_device_address (struct libusb_context *ctx, int detached,
 int linux_get_device_address (struct libusb_context *ctx, int detached,
-			      uint8_t *busnum, uint8_t *devaddr,
-			      const char *dev_node, const char *sys_name);
+	uint8_t *busnum, uint8_t *devaddr, const char *dev_node,
+	const char *sys_name);
 int linux_enumerate_device(struct libusb_context *ctx,
 int linux_enumerate_device(struct libusb_context *ctx,
-			   uint8_t busnum, uint8_t devaddr,
-			   const char *sysfs_dir);
+	uint8_t busnum, uint8_t devaddr, const char *sysfs_dir);
 
 
 #endif
 #endif

+ 734 - 0
compat/libusb-1.0/libusb/os/netbsd_usb.c

@@ -0,0 +1,734 @@
+/*
+ * Copyright © 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 netbsd_get_device_list(struct libusb_context *,
+    struct discovered_devs **);
+static int netbsd_open(struct libusb_device_handle *);
+static void netbsd_close(struct libusb_device_handle *);
+
+static int netbsd_get_device_descriptor(struct libusb_device *, unsigned char *,
+    int *);
+static int netbsd_get_active_config_descriptor(struct libusb_device *,
+    unsigned char *, size_t, int *);
+static int netbsd_get_config_descriptor(struct libusb_device *, uint8_t,
+    unsigned char *, size_t, int *);
+
+static int netbsd_get_configuration(struct libusb_device_handle *, int *);
+static int netbsd_set_configuration(struct libusb_device_handle *, int);
+
+static int netbsd_claim_interface(struct libusb_device_handle *, int);
+static int netbsd_release_interface(struct libusb_device_handle *, int);
+
+static int netbsd_set_interface_altsetting(struct libusb_device_handle *, int,
+    int);
+static int netbsd_clear_halt(struct libusb_device_handle *, unsigned char);
+static int netbsd_reset_device(struct libusb_device_handle *);
+static void netbsd_destroy_device(struct libusb_device *);
+
+static int netbsd_submit_transfer(struct usbi_transfer *);
+static int netbsd_cancel_transfer(struct usbi_transfer *);
+static void netbsd_clear_transfer_priv(struct usbi_transfer *);
+static int netbsd_handle_events(struct libusb_context *ctx, struct pollfd *,
+    nfds_t, int);
+static int netbsd_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 netbsd_backend = {
+	"Synchronous NetBSD backend",
+	0,
+	NULL,				/* init() */
+	NULL,				/* exit() */
+	netbsd_get_device_list,
+	NULL,				/* hotplug_poll */
+	netbsd_open,
+	netbsd_close,
+
+	netbsd_get_device_descriptor,
+	netbsd_get_active_config_descriptor,
+	netbsd_get_config_descriptor,
+	NULL,				/* get_config_descriptor_by_value() */
+
+	netbsd_get_configuration,
+	netbsd_set_configuration,
+
+	netbsd_claim_interface,
+	netbsd_release_interface,
+
+	netbsd_set_interface_altsetting,
+	netbsd_clear_halt,
+	netbsd_reset_device,
+
+	NULL,				/* kernel_driver_active() */
+	NULL,				/* detach_kernel_driver() */
+	NULL,				/* attach_kernel_driver() */
+
+	netbsd_destroy_device,
+
+	netbsd_submit_transfer,
+	netbsd_cancel_transfer,
+	netbsd_clear_transfer_priv,
+
+	netbsd_handle_events,
+
+	netbsd_clock_gettime,
+	sizeof(struct device_priv),
+	sizeof(struct handle_priv),
+	0,				/* transfer_priv_size */
+	0,				/* add_iso_packet_size */
+};
+
+int
+netbsd_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) {
+			dev = libusb_ref_device(dev);
+		} else {
+			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);
+
+		libusb_unref_device(dev);
+	}
+
+	return (LIBUSB_SUCCESS);
+
+error:
+	close(fd);
+	libusb_unref_device(dev);
+	return _errno_to_libusb(err);
+}
+
+int
+netbsd_open(struct libusb_device_handle *handle)
+{
+	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
+	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
+
+	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
+netbsd_close(struct libusb_device_handle *handle)
+{
+	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
+	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
+
+	usbi_dbg("close: fd %d", dpriv->fd);
+
+	close(dpriv->fd);
+	dpriv->fd = -1;
+
+	usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]);
+
+	close(hpriv->pipe[0]);
+	close(hpriv->pipe[1]);
+}
+
+int
+netbsd_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
+netbsd_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 len;
+}
+
+int
+netbsd_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 len;
+}
+
+int
+netbsd_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
+netbsd_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
+netbsd_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
+netbsd_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
+netbsd_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
+netbsd_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
+netbsd_reset_device(struct libusb_device_handle *handle)
+{
+	usbi_dbg("");
+
+	return (LIBUSB_ERROR_NOT_SUPPORTED);
+}
+
+void
+netbsd_destroy_device(struct libusb_device *dev)
+{
+	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
+
+	usbi_dbg("");
+
+	free(dpriv->cdesc);
+}
+
+int
+netbsd_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
+netbsd_cancel_transfer(struct usbi_transfer *itransfer)
+{
+	usbi_dbg("");
+
+	return (LIBUSB_ERROR_NOT_SUPPORTED);
+}
+
+void
+netbsd_clear_transfer_priv(struct usbi_transfer *itransfer)
+{
+	usbi_dbg("");
+
+	/* Nothing to do */
+}
+
+int
+netbsd_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
+netbsd_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, libusbx 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);
+}

+ 215 - 119
compat/libusb-1.0/libusb/os/openbsd_usb.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
+ * Copyright © 2011-2013 Martin Pieuchot <mpi@openbsd.org>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -32,8 +32,8 @@
 #include "libusbi.h"
 #include "libusbi.h"
 
 
 struct device_priv {
 struct device_priv {
-	char devnode[16];
-	int fd;
+	char *devname;				/* name of the ugen(4) node */
+	int fd;					/* device file descriptor */
 
 
 	unsigned char *cdesc;			/* active config descriptor */
 	unsigned char *cdesc;			/* active config descriptor */
 	usb_device_descriptor_t ddesc;		/* usb device descriptor */
 	usb_device_descriptor_t ddesc;		/* usb device descriptor */
@@ -82,22 +82,28 @@ static int obsd_clock_gettime(int, struct timespec *);
  * Private functions
  * Private functions
  */
  */
 static int _errno_to_libusb(int);
 static int _errno_to_libusb(int);
-static int _cache_active_config_descriptor(struct libusb_device *, int);
+static int _cache_active_config_descriptor(struct libusb_device *);
 static int _sync_control_transfer(struct usbi_transfer *);
 static int _sync_control_transfer(struct usbi_transfer *);
 static int _sync_gen_transfer(struct usbi_transfer *);
 static int _sync_gen_transfer(struct usbi_transfer *);
 static int _access_endpoint(struct libusb_transfer *);
 static int _access_endpoint(struct libusb_transfer *);
 
 
+static int _bus_open(int);
+
+
 const struct usbi_os_backend openbsd_backend = {
 const struct usbi_os_backend openbsd_backend = {
 	"Synchronous OpenBSD backend",
 	"Synchronous OpenBSD backend",
+	0,
 	NULL,				/* init() */
 	NULL,				/* init() */
 	NULL,				/* exit() */
 	NULL,				/* exit() */
 	obsd_get_device_list,
 	obsd_get_device_list,
+	NULL,				/* hotplug_poll */
 	obsd_open,
 	obsd_open,
 	obsd_close,
 	obsd_close,
 
 
 	obsd_get_device_descriptor,
 	obsd_get_device_descriptor,
 	obsd_get_active_config_descriptor,
 	obsd_get_active_config_descriptor,
 	obsd_get_config_descriptor,
 	obsd_get_config_descriptor,
+	NULL,				/* get_config_descriptor_by_value() */
 
 
 	obsd_get_configuration,
 	obsd_get_configuration,
 	obsd_set_configuration,
 	obsd_set_configuration,
@@ -128,75 +134,105 @@ const struct usbi_os_backend openbsd_backend = {
 	0,				/* add_iso_packet_size */
 	0,				/* add_iso_packet_size */
 };
 };
 
 
+#define DEVPATH	"/dev/"
+#define USBDEV	DEVPATH "usb"
+
 int
 int
 obsd_get_device_list(struct libusb_context * ctx,
 obsd_get_device_list(struct libusb_context * ctx,
 	struct discovered_devs **discdevs)
 	struct discovered_devs **discdevs)
 {
 {
+	struct discovered_devs *ddd;
 	struct libusb_device *dev;
 	struct libusb_device *dev;
 	struct device_priv *dpriv;
 	struct device_priv *dpriv;
 	struct usb_device_info di;
 	struct usb_device_info di;
+	struct usb_device_ddesc dd;
 	unsigned long session_id;
 	unsigned long session_id;
-	char devnode[16];
-	int fd, err, i;
+	char devices[USB_MAX_DEVICES];
+	char busnode[16];
+	char *udevname;
+	int fd, addr, i, j;
 
 
 	usbi_dbg("");
 	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);
+	for (i = 0; i < 8; i++) {
+		snprintf(busnode, sizeof(busnode), USBDEV "%d", i);
 
 
-		if ((fd = open(devnode, O_RDONLY)) < 0) {
+		if ((fd = open(busnode, O_RDWR)) < 0) {
 			if (errno != ENOENT && errno != ENXIO)
 			if (errno != ENOENT && errno != ENXIO)
-				usbi_err(ctx, "could not open %s", devnode);
+				usbi_err(ctx, "could not open %s", busnode);
 			continue;
 			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;
+		bzero(devices, sizeof(devices));
+		for (addr = 1; addr < USB_MAX_DEVICES; addr++) {
+			if (devices[addr])
+				continue;
+
+			di.udi_addr = addr;
+			if (ioctl(fd, USB_DEVICEINFO, &di) < 0)
+				continue;
+
+			/*
+			 * XXX If ugen(4) is attached to the USB device
+			 * it will be used.
+			 */
+			udevname = NULL;
+			for (j = 0; j < USB_MAX_DEVNAMES; j++)
+				if (!strncmp("ugen", di.udi_devnames[j], 4)) {
+					udevname = strdup(di.udi_devnames[j]);
+					break;
+				}
+
+			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) {
+					close(fd);
+					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;
+				dpriv->fd = -1;
+				dpriv->cdesc = NULL;
+				dpriv->devname = udevname;
+
+				dd.udd_bus = di.udi_bus;
+				dd.udd_addr = di.udi_addr;
+				if (ioctl(fd, USB_DEVICE_GET_DDESC, &dd) < 0) {
+					libusb_unref_device(dev);
+					continue;
+				}
+				dpriv->ddesc = dd.udd_desc;
+
+				if (_cache_active_config_descriptor(dev)) {
+					libusb_unref_device(dev);
+					continue;
+				}
+
+				if (usbi_sanitize_device(dev))
+					libusb_unref_device(dev);
 			}
 			}
 
 
-			dpriv->cdesc = NULL;
-			if (_cache_active_config_descriptor(dev, fd)) {
-				err = errno;
-				goto error;
+			ddd = discovered_devs_append(*discdevs, dev);
+			if (ddd == NULL) {
+				close(fd);
+				return (LIBUSB_ERROR_NO_MEM);
 			}
 			}
 
 
-			if ((err = usbi_sanitize_device(dev)))
-				goto error;
+			*discdevs = ddd;
+			devices[addr] = 1;
 		}
 		}
-		close(fd);
 
 
-		if (discovered_devs_append(*discdevs, dev) == NULL)
-			return (LIBUSB_ERROR_NO_MEM);
+		close(fd);
 	}
 	}
 
 
 	return (LIBUSB_SUCCESS);
 	return (LIBUSB_SUCCESS);
-
-error:
-	close(fd);
-	libusb_unref_device(dev);
-	return _errno_to_libusb(err);
 }
 }
 
 
 int
 int
@@ -204,15 +240,21 @@ obsd_open(struct libusb_device_handle *handle)
 {
 {
 	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
 	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
 	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
 	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
+	char devnode[16];
 
 
-	dpriv->fd = open(dpriv->devnode, O_RDWR);
-	if (dpriv->fd < 0) {
-		dpriv->fd = open(dpriv->devnode, O_RDONLY);
+	if (dpriv->devname) {
+		/*
+		 * Only open ugen(4) attached devices read-write, all
+		 * read-only operations are done through the bus node.
+		 */
+		snprintf(devnode, sizeof(devnode), DEVPATH "%s.00",
+		    dpriv->devname);
+		dpriv->fd = open(devnode, O_RDWR);
 		if (dpriv->fd < 0)
 		if (dpriv->fd < 0)
 			return _errno_to_libusb(errno);
 			return _errno_to_libusb(errno);
-	}
 
 
-	usbi_dbg("open %s: fd %d", dpriv->devnode, dpriv->fd);
+		usbi_dbg("open %s: fd %d", devnode, dpriv->fd);
+	}
 
 
 	if (pipe(hpriv->pipe) < 0)
 	if (pipe(hpriv->pipe) < 0)
 		return _errno_to_libusb(errno);
 		return _errno_to_libusb(errno);
@@ -226,10 +268,12 @@ obsd_close(struct libusb_device_handle *handle)
 	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
 	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
 	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
 	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
 
 
-	usbi_dbg("close: fd %d", dpriv->fd);
+	if (dpriv->devname) {
+		usbi_dbg("close: fd %d", dpriv->fd);
 
 
-	close(dpriv->fd);
-	dpriv->fd = -1;
+		close(dpriv->fd);
+		dpriv->fd = -1;
+	}
 
 
 	usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]);
 	usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]);
 
 
@@ -257,9 +301,8 @@ obsd_get_active_config_descriptor(struct libusb_device *dev,
     unsigned char *buf, size_t len, int *host_endian)
     unsigned char *buf, size_t len, int *host_endian)
 {
 {
 	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
 	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
-	usb_config_descriptor_t *ucd;
+	usb_config_descriptor_t *ucd = (usb_config_descriptor_t *)dpriv->cdesc;
 
 
-	ucd = (usb_config_descriptor_t *) dpriv->cdesc;
 	len = MIN(len, UGETW(ucd->wTotalLength));
 	len = MIN(len, UGETW(ucd->wTotalLength));
 
 
 	usbi_dbg("len %d", len);
 	usbi_dbg("len %d", len);
@@ -268,58 +311,48 @@ obsd_get_active_config_descriptor(struct libusb_device *dev,
 
 
 	*host_endian = 0;
 	*host_endian = 0;
 
 
-	return (LIBUSB_SUCCESS);
+	return (len);
 }
 }
 
 
 int
 int
 obsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
 obsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
     unsigned char *buf, size_t len, int *host_endian)
     unsigned char *buf, size_t len, int *host_endian)
 {
 {
-	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
-	struct usb_full_desc ufd;
+	struct usb_device_fdesc udf;
 	int fd, err;
 	int fd, err;
 
 
-	usbi_dbg("index %d, len %d", idx, len);
+	if ((fd = _bus_open(dev->bus_number)) < 0)
+		return _errno_to_libusb(errno);
 
 
-	/* 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);
-	}
+	udf.udf_bus = dev->bus_number;
+	udf.udf_addr = dev->device_address;
+	udf.udf_config_index = idx;
+	udf.udf_size = len;
+	udf.udf_data = buf;
 
 
-	ufd.ufd_config_index = idx;
-	ufd.ufd_size = len;
-	ufd.ufd_data = buf;
+	usbi_dbg("index %d, len %d", udf.udf_config_index, len);
 
 
-	if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
+	if (ioctl(fd, USB_DEVICE_GET_FDESC, &udf) < 0) {
 		err = errno;
 		err = errno;
-		if (dpriv->fd < 0)
-			close(fd);
+		close(fd);
 		return _errno_to_libusb(err);
 		return _errno_to_libusb(err);
 	}
 	}
-
-	if (dpriv->fd < 0)
-		close(fd);
+	close(fd);
 
 
 	*host_endian = 0;
 	*host_endian = 0;
 
 
-	return (LIBUSB_SUCCESS);
+	return (len);
 }
 }
 
 
 int
 int
 obsd_get_configuration(struct libusb_device_handle *handle, int *config)
 obsd_get_configuration(struct libusb_device_handle *handle, int *config)
 {
 {
 	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
 	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
+	usb_config_descriptor_t *ucd = (usb_config_descriptor_t *)dpriv->cdesc;
 
 
-	usbi_dbg("");
+	*config = ucd->bConfigurationValue;
 
 
-	if (ioctl(dpriv->fd, USB_GET_CONFIG, config) < 0)
-		return _errno_to_libusb(errno);
-
-	usbi_dbg("configuration %d", *config);
+	usbi_dbg("bConfigurationValue %d", *config);
 
 
 	return (LIBUSB_SUCCESS);
 	return (LIBUSB_SUCCESS);
 }
 }
@@ -329,12 +362,15 @@ obsd_set_configuration(struct libusb_device_handle *handle, int config)
 {
 {
 	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
 	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
 
 
-	usbi_dbg("configuration %d", config);
+	if (dpriv->devname == NULL)
+		return (LIBUSB_ERROR_NOT_SUPPORTED);
+
+	usbi_dbg("bConfigurationValue %d", config);
 
 
 	if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
 	if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
 		return _errno_to_libusb(errno);
 		return _errno_to_libusb(errno);
 
 
-	return _cache_active_config_descriptor(handle->dev, dpriv->fd);
+	return _cache_active_config_descriptor(handle->dev);
 }
 }
 
 
 int
 int
@@ -369,6 +405,9 @@ obsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
 	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
 	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
 	struct usb_alt_interface intf;
 	struct usb_alt_interface intf;
 
 
+	if (dpriv->devname == NULL)
+		return (LIBUSB_ERROR_NOT_SUPPORTED);
+
 	usbi_dbg("iface %d, setting %d", iface, altsetting);
 	usbi_dbg("iface %d, setting %d", iface, altsetting);
 
 
 	memset(&intf, 0, sizeof(intf));
 	memset(&intf, 0, sizeof(intf));
@@ -385,19 +424,27 @@ obsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
 int
 int
 obsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
 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;
 	struct usb_ctl_request req;
+	int fd, err;
+
+	if ((fd = _bus_open(handle->dev->bus_number)) < 0)
+		return _errno_to_libusb(errno);
 
 
 	usbi_dbg("");
 	usbi_dbg("");
 
 
+	req.ucr_addr = handle->dev->device_address;
 	req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
 	req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
 	req.ucr_request.bRequest = UR_CLEAR_FEATURE;
 	req.ucr_request.bRequest = UR_CLEAR_FEATURE;
 	USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
 	USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
 	USETW(req.ucr_request.wIndex, endpoint);
 	USETW(req.ucr_request.wIndex, endpoint);
 	USETW(req.ucr_request.wLength, 0);
 	USETW(req.ucr_request.wLength, 0);
 
 
-	if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0)
-		return _errno_to_libusb(errno);
+	if (ioctl(fd, USB_REQUEST, &req) < 0) {
+		err = errno;
+		close(fd);
+		return _errno_to_libusb(err);
+	}
+	close(fd);
 
 
 	return (LIBUSB_SUCCESS);
 	return (LIBUSB_SUCCESS);
 }
 }
@@ -418,6 +465,7 @@ obsd_destroy_device(struct libusb_device *dev)
 	usbi_dbg("");
 	usbi_dbg("");
 
 
 	free(dpriv->cdesc);
 	free(dpriv->cdesc);
+	free(dpriv->devname);
 }
 }
 
 
 int
 int
@@ -557,6 +605,8 @@ obsd_clock_gettime(int clkid, struct timespec *tp)
 int
 int
 _errno_to_libusb(int err)
 _errno_to_libusb(int err)
 {
 {
+	usbi_dbg("error: %s (%d)", strerror(err), err);
+
 	switch (err) {
 	switch (err) {
 	case EIO:
 	case EIO:
 		return (LIBUSB_ERROR_IO);
 		return (LIBUSB_ERROR_IO);
@@ -566,52 +616,64 @@ _errno_to_libusb(int err)
 		return (LIBUSB_ERROR_NO_DEVICE);
 		return (LIBUSB_ERROR_NO_DEVICE);
 	case ENOMEM:
 	case ENOMEM:
 		return (LIBUSB_ERROR_NO_MEM);
 		return (LIBUSB_ERROR_NO_MEM);
+	case ETIMEDOUT:
+		return (LIBUSB_ERROR_TIMEOUT);
 	}
 	}
 
 
-	usbi_dbg("error: %s", strerror(err));
-
 	return (LIBUSB_ERROR_OTHER);
 	return (LIBUSB_ERROR_OTHER);
 }
 }
 
 
 int
 int
-_cache_active_config_descriptor(struct libusb_device *dev, int fd)
+_cache_active_config_descriptor(struct libusb_device *dev)
 {
 {
 	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
 	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
-	struct usb_config_desc ucd;
-	struct usb_full_desc ufd;
+	struct usb_device_cdesc udc;
+	struct usb_device_fdesc udf;
 	unsigned char* buf;
 	unsigned char* buf;
-	int len;
+	int fd, len, err;
 
 
-	usbi_dbg("fd %d", fd);
+	if ((fd = _bus_open(dev->bus_number)) < 0)
+		return _errno_to_libusb(errno);
 
 
-	ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX;
+	usbi_dbg("fd %d, addr %d", fd, dev->device_address);
 
 
-	if ((ioctl(fd, USB_GET_CONFIG_DESC, &ucd)) < 0)
+	udc.udc_bus = dev->bus_number;
+	udc.udc_addr = dev->device_address;
+	udc.udc_config_index = USB_CURRENT_CONFIG_INDEX;
+	if (ioctl(fd, USB_DEVICE_GET_CDESC, &udc) < 0) {
+		err = errno;
+		close(fd);
 		return _errno_to_libusb(errno);
 		return _errno_to_libusb(errno);
+	}
 
 
-	usbi_dbg("active bLength %d", ucd.ucd_desc.bLength);
+	usbi_dbg("active bLength %d", udc.udc_desc.bLength);
 
 
-	len = UGETW(ucd.ucd_desc.wTotalLength);
+	len = UGETW(udc.udc_desc.wTotalLength);
 	buf = malloc(len);
 	buf = malloc(len);
 	if (buf == NULL)
 	if (buf == NULL)
 		return (LIBUSB_ERROR_NO_MEM);
 		return (LIBUSB_ERROR_NO_MEM);
 
 
-	ufd.ufd_config_index = ucd.ucd_config_index;
-	ufd.ufd_size = len;
-	ufd.ufd_data = buf;
+	udf.udf_bus = dev->bus_number;
+	udf.udf_addr = dev->device_address;
+	udf.udf_config_index = udc.udc_config_index;
+	udf.udf_size = len;
+	udf.udf_data = buf;
 
 
-	usbi_dbg("index %d, len %d", ufd.ufd_config_index, len);
+	usbi_dbg("index %d, len %d", udf.udf_config_index, len);
 
 
-	if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
+	if (ioctl(fd, USB_DEVICE_GET_FDESC, &udf) < 0) {
+		err = errno;
+		close(fd);
 		free(buf);
 		free(buf);
-		return _errno_to_libusb(errno);
+		return _errno_to_libusb(err);
 	}
 	}
+	close(fd);
 
 
 	if (dpriv->cdesc)
 	if (dpriv->cdesc)
 		free(dpriv->cdesc);
 		free(dpriv->cdesc);
 	dpriv->cdesc = buf;
 	dpriv->cdesc = buf;
 
 
-	return (0);
+	return (LIBUSB_SUCCESS);
 }
 }
 
 
 int
 int
@@ -626,15 +688,16 @@ _sync_control_transfer(struct usbi_transfer *itransfer)
 	dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
 	dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
 	setup = (struct libusb_control_setup *)transfer->buffer;
 	setup = (struct libusb_control_setup *)transfer->buffer;
 
 
-	usbi_dbg("type %d request %d value %d index %d length %d timeout %d",
+	usbi_dbg("type %x request %x value %x index %d length %d timeout %d",
 	    setup->bmRequestType, setup->bRequest,
 	    setup->bmRequestType, setup->bRequest,
 	    libusb_le16_to_cpu(setup->wValue),
 	    libusb_le16_to_cpu(setup->wValue),
 	    libusb_le16_to_cpu(setup->wIndex),
 	    libusb_le16_to_cpu(setup->wIndex),
 	    libusb_le16_to_cpu(setup->wLength), transfer->timeout);
 	    libusb_le16_to_cpu(setup->wLength), transfer->timeout);
 
 
+	req.ucr_addr = transfer->dev_handle->dev->device_address;
 	req.ucr_request.bmRequestType = setup->bmRequestType;
 	req.ucr_request.bmRequestType = setup->bmRequestType;
 	req.ucr_request.bRequest = setup->bRequest;
 	req.ucr_request.bRequest = setup->bRequest;
-	/* Don't use USETW, libusb already deals with the endianness */
+	/* Don't use USETW, libusbx already deals with the endianness */
 	(*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
 	(*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
 	(*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
 	(*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
 	(*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
 	(*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
@@ -643,11 +706,30 @@ _sync_control_transfer(struct usbi_transfer *itransfer)
 	if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
 	if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
 		req.ucr_flags = USBD_SHORT_XFER_OK;
 		req.ucr_flags = USBD_SHORT_XFER_OK;
 
 
-	if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
-		return _errno_to_libusb(errno);
+	if (dpriv->devname == NULL) {
+		/*
+		 * XXX If the device is not attached to ugen(4) it is
+		 * XXX still possible to submit a control transfer but
+		 * XXX with the default timeout only.
+		 */
+		int fd, err;
 
 
-	if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0)
-		return _errno_to_libusb(errno);
+		if ((fd = _bus_open(transfer->dev_handle->dev->bus_number)) < 0)
+			return _errno_to_libusb(errno);
+
+		if ((ioctl(fd, USB_REQUEST, &req)) < 0) {
+			err = errno;
+			close(fd);
+			return _errno_to_libusb(err);
+		}
+		close(fd);
+	} else {
+		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;
 	itransfer->transferred = req.ucr_actlen;
 
 
@@ -661,7 +743,7 @@ _access_endpoint(struct libusb_transfer *transfer)
 {
 {
 	struct handle_priv *hpriv;
 	struct handle_priv *hpriv;
 	struct device_priv *dpriv;
 	struct device_priv *dpriv;
-	char *s, devnode[16];
+	char devnode[16];
 	int fd, endpt;
 	int fd, endpt;
 	mode_t mode;
 	mode_t mode;
 
 
@@ -674,10 +756,9 @@ _access_endpoint(struct libusb_transfer *transfer)
 	usbi_dbg("endpoint %d mode %d", endpt, mode);
 	usbi_dbg("endpoint %d mode %d", endpt, mode);
 
 
 	if (hpriv->endpoints[endpt] < 0) {
 	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);
+		/* Pick the right endpoint node */
+		snprintf(devnode, sizeof(devnode), DEVPATH "%s.%02d",
+		    dpriv->devname, endpt);
 
 
 		/* We may need to read/write to the same endpoint later. */
 		/* We may need to read/write to the same endpoint later. */
 		if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
 		if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
@@ -694,9 +775,14 @@ int
 _sync_gen_transfer(struct usbi_transfer *itransfer)
 _sync_gen_transfer(struct usbi_transfer *itransfer)
 {
 {
 	struct libusb_transfer *transfer;
 	struct libusb_transfer *transfer;
+	struct device_priv *dpriv;
 	int fd, nr = 1;
 	int fd, nr = 1;
 
 
 	transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
 	transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+	dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
+
+	if (dpriv->devname == NULL)
+		return (LIBUSB_ERROR_NOT_SUPPORTED);
 
 
 	/*
 	/*
 	 * Bulk, Interrupt or Isochronous transfer depends on the
 	 * Bulk, Interrupt or Isochronous transfer depends on the
@@ -725,3 +811,13 @@ _sync_gen_transfer(struct usbi_transfer *itransfer)
 
 
 	return (0);
 	return (0);
 }
 }
+
+int
+_bus_open(int number)
+{
+	char busnode[16];
+
+	snprintf(busnode, sizeof(busnode), USBDEV "%d", number);
+
+	return open(busnode, O_RDWR);
+}

+ 51 - 0
compat/libusb-1.0/libusb/os/poll_posix.c

@@ -0,0 +1,51 @@
+/*
+ * poll_posix: poll compatibility wrapper for POSIX systems
+ * Copyright © 2013 RealVNC Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "libusbi.h"
+
+int usbi_pipe(int pipefd[2])
+{
+	int ret = pipe(pipefd);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = fcntl(pipefd[1], F_GETFL);
+	if (ret == -1) {
+		usbi_dbg("Failed to get pipe fd flags: %d", errno);
+		goto err_close_pipe;
+	}
+	ret = fcntl(pipefd[1], F_SETFL, ret | O_NONBLOCK);
+	if (ret != 0) {
+		usbi_dbg("Failed to set non-blocking on new pipe: %d", errno);
+		goto err_close_pipe;
+	}
+
+	return 0;
+
+err_close_pipe:
+	usbi_close(pipefd[0]);
+	usbi_close(pipefd[1]);
+	return ret;
+}

+ 2 - 1
compat/libusb-1.0/libusb/os/poll_posix.h

@@ -4,7 +4,8 @@
 #define usbi_write write
 #define usbi_write write
 #define usbi_read read
 #define usbi_read read
 #define usbi_close close
 #define usbi_close close
-#define usbi_pipe pipe
 #define usbi_poll poll
 #define usbi_poll poll
 
 
+int usbi_pipe(int pipefd[2]);
+
 #endif /* LIBUSB_POLL_POSIX_H */
 #endif /* LIBUSB_POLL_POSIX_H */

+ 92 - 111
compat/libusb-1.0/libusb/os/poll_windows.c

@@ -1,6 +1,7 @@
 /*
 /*
  * poll_windows: poll compatibility wrapper for Windows
  * poll_windows: poll compatibility wrapper for Windows
- * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com>
+ * Copyright © 2012-2013 RealVNC Ltd.
+ * Copyright © 2009-2010 Pete Batard <pete@akeo.ie>
  * With contributions from Michael Plante, Orin Eman et al.
  * With contributions from Michael Plante, Orin Eman et al.
  * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
  * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
  *
  *
@@ -21,7 +22,7 @@
  */
  */
 
 
 /*
 /*
- * poll() and pipe() Windows compatibility layer for libusb 1.0
+ * poll() and pipe() Windows compatibility layer for libusbx 1.0
  *
  *
  * The way this layer works is by using OVERLAPPED with async I/O transfers, as
  * 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.
  * OVERLAPPED have an associated event which is flagged for I/O completion.
@@ -31,7 +32,7 @@
  *   OVERLAPPED mode
  *   OVERLAPPED mode
  * - call usbi_create_fd with this handle to obtain a custom fd.
  * - 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
  *   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
+ *   twice, once in RW_READ and once in RW_WRITE mode to obtain 2 separate
  *   pollable fds
  *   pollable fds
  * - leave the core functions call the poll routine and flag POLLIN/POLLOUT
  * - leave the core functions call the poll routine and flag POLLIN/POLLOUT
  *
  *
@@ -40,12 +41,10 @@
  * context.
  * context.
  */
  */
 #include <errno.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
-#include <io.h>
 
 
-#include <libusbi.h>
+#include "libusbi.h"
 
 
 // Uncomment to debug the polling layer
 // Uncomment to debug the polling layer
 //#define DEBUG_POLL_WINDOWS
 //#define DEBUG_POLL_WINDOWS
@@ -53,8 +52,8 @@
 #define poll_dbg usbi_dbg
 #define poll_dbg usbi_dbg
 #else
 #else
 // MSVC++ < 2005 cannot use a variadic argument and non MSVC
 // MSVC++ < 2005 cannot use a variadic argument and non MSVC
-// compilers produce warnings if parenthesis are omitted.
-#if defined(_MSC_VER) && _MSC_VER < 1400
+// compilers produce warnings if parenthesis are ommitted.
+#if defined(_MSC_VER) && (_MSC_VER < 1400)
 #define poll_dbg
 #define poll_dbg
 #else
 #else
 #define poll_dbg(...)
 #define poll_dbg(...)
@@ -65,20 +64,10 @@
 #pragma warning(disable:28719)
 #pragma warning(disable:28719)
 #endif
 #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)
 #define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0)
 
 
 // public fd data
 // public fd data
-const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, RW_NONE};
+const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, NULL, NULL, RW_NONE};
 struct winfd poll_fd[MAX_FDS];
 struct winfd poll_fd[MAX_FDS];
 // internal fd data
 // internal fd data
 struct {
 struct {
@@ -93,12 +82,25 @@ BOOLEAN is_polling_set = FALSE;
 LONG pipe_number = 0;
 LONG pipe_number = 0;
 static volatile LONG compat_spinlock = 0;
 static volatile LONG compat_spinlock = 0;
 
 
+#if !defined(_WIN32_WCE)
 // CancelIoEx, available on Vista and later only, provides the ability to cancel
 // 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
 // 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.
 // platform headers, we hook into the Kernel32 system DLL directly to seek it.
 static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
 static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
-#define CancelIoEx_Available (pCancelIoEx != NULL)
-static __inline BOOL cancel_io(int _index)
+#define Use_Duplicate_Handles (pCancelIoEx == NULL)
+
+static inline void setup_cancel_io(void)
+{
+	HMODULE hKernel32 = GetModuleHandleA("KERNEL32");
+	if (hKernel32 != NULL) {
+		pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED))
+			GetProcAddress(hKernel32, "CancelIoEx");
+	}
+	usbi_dbg("Will use CancelIo%s for I/O cancellation",
+		Use_Duplicate_Handles?"":"Ex");
+}
+
+static inline BOOL cancel_io(int _index)
 {
 {
 	if ((_index < 0) || (_index >= MAX_FDS)) {
 	if ((_index < 0) || (_index >= MAX_FDS)) {
 		return FALSE;
 		return FALSE;
@@ -108,7 +110,12 @@ static __inline BOOL cancel_io(int _index)
 	  || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) {
 	  || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) {
 		return TRUE;
 		return TRUE;
 	}
 	}
-	if (CancelIoEx_Available) {
+	if (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) {
+		// Cancel outstanding transfer via the specific callback
+		(*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer);
+		return TRUE;
+	}
+	if (pCancelIoEx != NULL) {
 		return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped);
 		return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped);
 	}
 	}
 	if (_poll_fd[_index].thread_id == GetCurrentThreadId()) {
 	if (_poll_fd[_index].thread_id == GetCurrentThreadId()) {
@@ -117,6 +124,30 @@ static __inline BOOL cancel_io(int _index)
 	usbi_warn(NULL, "Unable to cancel I/O that was started from another thread");
 	usbi_warn(NULL, "Unable to cancel I/O that was started from another thread");
 	return FALSE;
 	return FALSE;
 }
 }
+#else
+#define Use_Duplicate_Handles FALSE
+
+static __inline void setup_cancel_io()
+{
+	// No setup needed on WinCE
+}
+
+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 (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) {
+		// Cancel outstanding transfer via the specific callback
+		(*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer);
+	}
+	return TRUE;
+}
+#endif
 
 
 // Init
 // Init
 void init_polling(void)
 void init_polling(void)
@@ -127,10 +158,7 @@ void init_polling(void)
 		SleepEx(0, TRUE);
 		SleepEx(0, TRUE);
 	}
 	}
 	if (!is_polling_set) {
 	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":"");
+		setup_cancel_io();
 		for (i=0; i<MAX_FDS; i++) {
 		for (i=0; i<MAX_FDS; i++) {
 			poll_fd[i] = INVALID_WINFD;
 			poll_fd[i] = INVALID_WINFD;
 			_poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
 			_poll_fd[i].original_handle = INVALID_HANDLE_VALUE;
@@ -139,15 +167,15 @@ void init_polling(void)
 		}
 		}
 		is_polling_set = TRUE;
 		is_polling_set = TRUE;
 	}
 	}
-	compat_spinlock = 0;
+	InterlockedExchange((LONG *)&compat_spinlock, 0);
 }
 }
 
 
 // Internal function to retrieve the table index (and lock the fd mutex)
 // Internal function to retrieve the table index (and lock the fd mutex)
-int _fd_to_index_and_lock(int fd)
+static int _fd_to_index_and_lock(int fd)
 {
 {
 	int i;
 	int i;
 
 
-	if (fd <= 0)
+	if (fd < 0)
 		return -1;
 		return -1;
 
 
 	for (i=0; i<MAX_FDS; i++) {
 	for (i=0; i<MAX_FDS; i++) {
@@ -164,7 +192,7 @@ int _fd_to_index_and_lock(int fd)
 	return -1;
 	return -1;
 }
 }
 
 
-OVERLAPPED *create_overlapped(void)
+static OVERLAPPED *create_overlapped(void)
 {
 {
 	OVERLAPPED *overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED));
 	OVERLAPPED *overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED));
 	if (overlapped == NULL) {
 	if (overlapped == NULL) {
@@ -178,7 +206,7 @@ OVERLAPPED *create_overlapped(void)
 	return overlapped;
 	return overlapped;
 }
 }
 
 
-void free_overlapped(OVERLAPPED *overlapped)
+static void free_overlapped(OVERLAPPED *overlapped)
 {
 {
 	if (overlapped == NULL)
 	if (overlapped == NULL)
 		return;
 		return;
@@ -190,20 +218,6 @@ void free_overlapped(OVERLAPPED *overlapped)
 	free(overlapped);
 	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)
 void exit_polling(void)
 {
 {
 	int i;
 	int i;
@@ -221,12 +235,8 @@ void exit_polling(void)
 			// terminating, and we should be able to access the fd
 			// terminating, and we should be able to access the fd
 			// mutex lock before too long
 			// mutex lock before too long
 			EnterCriticalSection(&_poll_fd[i].mutex);
 			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);
 			free_overlapped(poll_fd[i].overlapped);
-			if (!CancelIoEx_Available) {
+			if (Use_Duplicate_Handles) {
 				// Close duplicate handle
 				// Close duplicate handle
 				if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) {
 				if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) {
 					CloseHandle(poll_fd[i].handle);
 					CloseHandle(poll_fd[i].handle);
@@ -237,12 +247,12 @@ void exit_polling(void)
 			DeleteCriticalSection(&_poll_fd[i].mutex);
 			DeleteCriticalSection(&_poll_fd[i].mutex);
 		}
 		}
 	}
 	}
-	compat_spinlock = 0;
+	InterlockedExchange((LONG *)&compat_spinlock, 0);
 }
 }
 
 
 /*
 /*
  * Create a fake pipe.
  * Create a fake pipe.
- * As libusb only uses pipes for signaling, all we need from a pipe is an
+ * As libusbx 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
  * event. To that extent, we create a single wfd and overlapped as a means
  * to access that event.
  * to access that event.
  */
  */
@@ -253,7 +263,8 @@ int usbi_pipe(int filedes[2])
 
 
 	CHECK_INIT_POLLING;
 	CHECK_INIT_POLLING;
 
 
-	overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED));
+	overlapped = create_overlapped();
+
 	if (overlapped == NULL) {
 	if (overlapped == NULL) {
 		return -1;
 		return -1;
 	}
 	}
@@ -261,22 +272,6 @@ int usbi_pipe(int filedes[2])
 	overlapped->Internal = STATUS_PENDING;
 	overlapped->Internal = STATUS_PENDING;
 	overlapped->InternalHigh = 0;
 	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++) {
 	for (i=0; i<MAX_FDS; i++) {
 		if (poll_fd[i].fd < 0) {
 		if (poll_fd[i].fd < 0) {
 			EnterCriticalSection(&_poll_fd[i].mutex);
 			EnterCriticalSection(&_poll_fd[i].mutex);
@@ -286,7 +281,13 @@ int usbi_pipe(int filedes[2])
 				continue;
 				continue;
 			}
 			}
 
 
-			poll_fd[i].fd = filedes[0];
+			// Use index as the unique fd number
+			poll_fd[i].fd = i;
+			// Read end of the "pipe"
+			filedes[0] = poll_fd[i].fd;
+			// We can use the same handle for both ends
+			filedes[1] = filedes[0];
+
 			poll_fd[i].handle = DUMMY_HANDLE;
 			poll_fd[i].handle = DUMMY_HANDLE;
 			poll_fd[i].overlapped = overlapped;
 			poll_fd[i].overlapped = overlapped;
 			// There's no polling on the write end, so we just use READ for our needs
 			// There's no polling on the write end, so we just use READ for our needs
@@ -296,12 +297,7 @@ int usbi_pipe(int filedes[2])
 			return 0;
 			return 0;
 		}
 		}
 	}
 	}
-
-	CloseHandle(overlapped->hEvent);
-out2:
-	_close(filedes[0]);
-out1:
-	free(overlapped);
+	free_overlapped(overlapped);
 	return -1;
 	return -1;
 }
 }
 
 
@@ -319,9 +315,9 @@ out1:
  * read and one for write. Using a single R/W fd is unsupported and will
  * read and one for write. Using a single R/W fd is unsupported and will
  * produce unexpected results
  * produce unexpected results
  */
  */
-struct winfd usbi_create_fd(HANDLE handle, int access_mode)
+struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct usbi_transfer *itransfer, cancel_transfer *cancel_fn)
 {
 {
-	int i, fd;
+	int i;
 	struct winfd wfd = INVALID_WINFD;
 	struct winfd wfd = INVALID_WINFD;
 	OVERLAPPED* overlapped = NULL;
 	OVERLAPPED* overlapped = NULL;
 
 
@@ -331,27 +327,22 @@ struct winfd usbi_create_fd(HANDLE handle, int access_mode)
 		return INVALID_WINFD;
 		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"
+	wfd.itransfer = itransfer;
+	wfd.cancel_fn = cancel_fn;
+
+	if ((access_mode != RW_READ) && (access_mode != RW_WRITE)) {
+		usbi_warn(NULL, "only one of RW_READ or RW_WRITE are supported.\n"
 			"If you want to poll for R/W simultaneously, create multiple fds from the same handle.");
 			"If you want to poll for R/W simultaneously, create multiple fds from the same handle.");
 		return INVALID_WINFD;
 		return INVALID_WINFD;
 	}
 	}
-	if (access_mode == _O_RDONLY) {
+	if (access_mode == RW_READ) {
 		wfd.rw = RW_READ;
 		wfd.rw = RW_READ;
 	} else {
 	} else {
 		wfd.rw = RW_WRITE;
 		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();
 	overlapped = create_overlapped();
 	if(overlapped == NULL) {
 	if(overlapped == NULL) {
-		_close(fd);
 		return INVALID_WINFD;
 		return INVALID_WINFD;
 	}
 	}
 
 
@@ -363,10 +354,11 @@ struct winfd usbi_create_fd(HANDLE handle, int access_mode)
 				LeaveCriticalSection(&_poll_fd[i].mutex);
 				LeaveCriticalSection(&_poll_fd[i].mutex);
 				continue;
 				continue;
 			}
 			}
-			wfd.fd = fd;
+			// Use index as the unique fd number
+			wfd.fd = i;
 			// Attempt to emulate some of the CancelIoEx behaviour on platforms
 			// Attempt to emulate some of the CancelIoEx behaviour on platforms
 			// that don't have it
 			// that don't have it
-			if (!CancelIoEx_Available) {
+			if (Use_Duplicate_Handles) {
 				_poll_fd[i].thread_id = GetCurrentThreadId();
 				_poll_fd[i].thread_id = GetCurrentThreadId();
 				if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
 				if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
 					&wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
 					&wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
@@ -387,21 +379,15 @@ struct winfd usbi_create_fd(HANDLE handle, int access_mode)
 		}
 		}
 	}
 	}
 	free_overlapped(overlapped);
 	free_overlapped(overlapped);
-	_close(fd);
 	return INVALID_WINFD;
 	return INVALID_WINFD;
 }
 }
 
 
-void _free_index(int _index)
+static void _free_index(int _index)
 {
 {
 	// Cancel any async IO (Don't care about the validity of our handles for this)
 	// Cancel any async IO (Don't care about the validity of our handles for this)
 	cancel_io(_index);
 	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)
 	// close the duplicate handle (if we have an actual duplicate)
-	if (!CancelIoEx_Available) {
+	if (Use_Duplicate_Handles) {
 		if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) {
 		if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) {
 			CloseHandle(poll_fd[_index].handle);
 			CloseHandle(poll_fd[_index].handle);
 		}
 		}
@@ -417,17 +403,18 @@ void _free_index(int _index)
  *
  *
  * Note that the associated Windows handle is not closed by this call
  * Note that the associated Windows handle is not closed by this call
  */
  */
-void usbi_free_fd(int fd)
+void usbi_free_fd(struct winfd *wfd)
 {
 {
 	int _index;
 	int _index;
 
 
 	CHECK_INIT_POLLING;
 	CHECK_INIT_POLLING;
 
 
-	_index = _fd_to_index_and_lock(fd);
+	_index = _fd_to_index_and_lock(wfd->fd);
 	if (_index < 0) {
 	if (_index < 0) {
 		return;
 		return;
 	}
 	}
 	_free_index(_index);
 	_free_index(_index);
+	*wfd = INVALID_WINFD;
 	LeaveCriticalSection(&_poll_fd[_index].mutex);
 	LeaveCriticalSection(&_poll_fd[_index].mutex);
 }
 }
 
 
@@ -441,7 +428,7 @@ struct winfd fd_to_winfd(int fd)
 
 
 	CHECK_INIT_POLLING;
 	CHECK_INIT_POLLING;
 
 
-	if (fd <= 0)
+	if (fd < 0)
 		return INVALID_WINFD;
 		return INVALID_WINFD;
 
 
 	for (i=0; i<MAX_FDS; i++) {
 	for (i=0; i<MAX_FDS; i++) {
@@ -651,15 +638,7 @@ int usbi_close(int fd)
 	if (_index < 0) {
 	if (_index < 0) {
 		errno = EBADF;
 		errno = EBADF;
 	} else {
 	} 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;
-		}
+		free_overlapped(poll_fd[_index].overlapped);
 		poll_fd[_index] = INVALID_WINFD;
 		poll_fd[_index] = INVALID_WINFD;
 		LeaveCriticalSection(&_poll_fd[_index].mutex);
 		LeaveCriticalSection(&_poll_fd[_index].mutex);
 	}
 	}
@@ -672,6 +651,7 @@ int usbi_close(int fd)
 ssize_t usbi_write(int fd, const void *buf, size_t count)
 ssize_t usbi_write(int fd, const void *buf, size_t count)
 {
 {
 	int _index;
 	int _index;
+	UNUSED(buf);
 
 
 	CHECK_INIT_POLLING;
 	CHECK_INIT_POLLING;
 
 
@@ -708,6 +688,7 @@ ssize_t usbi_read(int fd, void *buf, size_t count)
 {
 {
 	int _index;
 	int _index;
 	ssize_t r = -1;
 	ssize_t r = -1;
+	UNUSED(buf);
 
 
 	CHECK_INIT_POLLING;
 	CHECK_INIT_POLLING;
 
 

+ 14 - 6
compat/libusb-1.0/libusb/os/poll_windows.h

@@ -1,6 +1,7 @@
 /*
 /*
  * Windows compat: POSIX compatibility wrapper
  * Windows compat: POSIX compatibility wrapper
- * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com>
+ * Copyright © 2012-2013 RealVNC Ltd.
+ * Copyright © 2009-2010 Pete Batard <pete@akeo.ie>
  * With contributions from Michael Plante, Orin Eman et al.
  * With contributions from Michael Plante, Orin Eman et al.
  * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
  * Parts of poll implementation from libusb-win32, by Stephan Meyer et al.
  *
  *
@@ -21,8 +22,6 @@
  */
  */
 #pragma once
 #pragma once
 
 
-#include <windows.h>
-
 #if defined(_MSC_VER)
 #if defined(_MSC_VER)
 // disable /W4 MSVC warnings that are benign
 // disable /W4 MSVC warnings that are benign
 #pragma warning(disable:4127) // conditional expression is constant
 #pragma warning(disable:4127) // conditional expression is constant
@@ -33,12 +32,17 @@
 #define STATUS_REPARSE ((LONG)0x00000104L)
 #define STATUS_REPARSE ((LONG)0x00000104L)
 #endif
 #endif
 #define STATUS_COMPLETED_SYNCHRONOUSLY	STATUS_REPARSE
 #define STATUS_COMPLETED_SYNCHRONOUSLY	STATUS_REPARSE
+#if defined(_WIN32_WCE)
+// WinCE doesn't have a HasOverlappedIoCompleted() macro, so attempt to emulate it
+#define HasOverlappedIoCompleted(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) != STATUS_PENDING)
+#endif
 #define HasOverlappedIoCompletedSync(lpOverlapped)	(((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY)
 #define HasOverlappedIoCompletedSync(lpOverlapped)	(((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY)
 
 
 #define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2)
 #define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2)
 
 
 enum windows_version {
 enum windows_version {
 	WINDOWS_UNSUPPORTED,
 	WINDOWS_UNSUPPORTED,
+	WINDOWS_CE,
 	WINDOWS_XP,
 	WINDOWS_XP,
 	WINDOWS_2003,	// also includes XP 64
 	WINDOWS_2003,	// also includes XP 64
 	WINDOWS_VISTA_AND_LATER,
 	WINDOWS_VISTA_AND_LATER,
@@ -68,10 +72,14 @@ enum rw_type {
 };
 };
 
 
 // fd struct that can be used for polling on Windows
 // fd struct that can be used for polling on Windows
+typedef int cancel_transfer(struct usbi_transfer *itransfer);
+
 struct winfd {
 struct winfd {
 	int fd;							// what's exposed to libusb core
 	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
 	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
 	OVERLAPPED* overlapped;			// what will report our I/O status
+	struct usbi_transfer *itransfer;		// Associated transfer, or NULL if completed
+	cancel_transfer *cancel_fn;		// Function pointer to cancel transfer API
 	enum rw_type rw;				// I/O transfer direction: read *XOR* write (NOT BOTH)
 	enum rw_type rw;				// I/O transfer direction: read *XOR* write (NOT BOTH)
 };
 };
 extern const struct winfd INVALID_WINFD;
 extern const struct winfd INVALID_WINFD;
@@ -84,8 +92,9 @@ int usbi_close(int fd);
 
 
 void init_polling(void);
 void init_polling(void);
 void exit_polling(void);
 void exit_polling(void);
-struct winfd usbi_create_fd(HANDLE handle, int access_mode);
-void usbi_free_fd(int fd);
+struct winfd usbi_create_fd(HANDLE handle, int access_mode, 
+	struct usbi_transfer *transfer, cancel_transfer *cancel_fn);
+void usbi_free_fd(struct winfd* winfd);
 struct winfd fd_to_winfd(int fd);
 struct winfd fd_to_winfd(int fd);
 struct winfd handle_to_winfd(HANDLE handle);
 struct winfd handle_to_winfd(HANDLE handle);
 struct winfd overlapped_to_winfd(OVERLAPPED* overlapped);
 struct winfd overlapped_to_winfd(OVERLAPPED* overlapped);
@@ -114,4 +123,3 @@ do {                                                    \
 	}                                                   \
 	}                                                   \
 } while (0)
 } while (0)
 #endif
 #endif
-

+ 37 - 10
compat/libusb-1.0/libusb/os/threads_posix.c

@@ -1,8 +1,8 @@
 /*
 /*
- * libusb synchronization using POSIX Threads
+ * libusbx synchronization using POSIX Threads
  *
  *
- * Copyright (C) 2011 Vitali Lovich <vlovich@aliph.com>
- * Copyright (C) 2011 Peter Stuge <peter@stuge.se>
+ * Copyright © 2011 Vitali Lovich <vlovich@aliph.com>
+ * Copyright © 2011 Peter Stuge <peter@stuge.se>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -19,14 +19,19 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  * 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
+#if defined(__linux__) || defined(__OpenBSD__)
+# if defined(__linux__)
+#  define _GNU_SOURCE
+# else
+#  define _BSD_SOURCE
 # endif
 # endif
-#else
-#define _XOPEN_SOURCE 500
-#endif /* _XOPEN_SOURCE */
+# include <unistd.h>
+# include <sys/syscall.h>
+#elif defined(__APPLE__)
+# include <mach/mach.h>
+#elif defined(__CYGWIN__)
+# include <windows.h>
+#endif
 
 
 #include "threads_posix.h"
 #include "threads_posix.h"
 
 
@@ -41,6 +46,7 @@ int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
 			return err;
 			return err;
 	}
 	}
 
 
+	/* mutexattr_settype requires _GNU_SOURCE or _XOPEN_SOURCE >= 500 on Linux */
 	err = pthread_mutexattr_settype(attr, PTHREAD_MUTEX_RECURSIVE);
 	err = pthread_mutexattr_settype(attr, PTHREAD_MUTEX_RECURSIVE);
 	if (err != 0)
 	if (err != 0)
 		goto finish;
 		goto finish;
@@ -53,3 +59,24 @@ finish:
 
 
 	return err;
 	return err;
 }
 }
+
+int usbi_get_tid(void)
+{
+	int ret = -1;
+#if defined(__ANDROID__)
+	ret = gettid();
+#elif defined(__linux__)
+	ret = syscall(SYS_gettid);
+#elif defined(__OpenBSD__)
+	/* The following only works with OpenBSD > 5.1 as it requires
+	   real thread support. For 5.1 and earlier, -1 is returned. */
+	ret = syscall(SYS_getthrid);
+#elif defined(__APPLE__)
+	ret = mach_thread_self();
+	mach_port_deallocate(mach_task_self(), ret);
+#elif defined(__CYGWIN__)
+	ret = GetCurrentThreadId();
+#endif
+/* TODO: NetBSD thread ID support */
+	return ret;
+}

+ 4 - 2
compat/libusb-1.0/libusb/os/threads_posix.h

@@ -1,7 +1,7 @@
 /*
 /*
- * libusb synchronization using POSIX Threads
+ * libusbx synchronization using POSIX Threads
  *
  *
- * Copyright (C) 2010 Peter Stuge <peter@stuge.se>
+ * Copyright © 2010 Peter Stuge <peter@stuge.se>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -45,4 +45,6 @@
 
 
 extern int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
 extern int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
 
 
+int usbi_get_tid(void);
+
 #endif /* LIBUSB_THREADS_POSIX_H */
 #endif /* LIBUSB_THREADS_POSIX_H */

+ 16 - 12
compat/libusb-1.0/libusb/os/threads_windows.c

@@ -1,7 +1,7 @@
 /*
 /*
- * libusb synchronization on Microsoft Windows
+ * libusbx synchronization on Microsoft Windows
  *
  *
- * Copyright (C) 2010 Michael Plante <michael.plante@gmail.com>
+ * Copyright © 2010 Michael Plante <michael.plante@gmail.com>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -25,9 +25,11 @@
 
 
 #include "libusbi.h"
 #include "libusbi.h"
 
 
+extern const uint64_t epoch_time;
 
 
 int usbi_mutex_init(usbi_mutex_t *mutex,
 int usbi_mutex_init(usbi_mutex_t *mutex,
 					const usbi_mutexattr_t *attr) {
 					const usbi_mutexattr_t *attr) {
+	UNUSED(attr);
 	if(! mutex) return ((errno=EINVAL));
 	if(! mutex) return ((errno=EINVAL));
 	*mutex = CreateMutex(NULL, FALSE, NULL);
 	*mutex = CreateMutex(NULL, FALSE, NULL);
 	if(!*mutex) return ((errno=ENOMEM));
 	if(!*mutex) return ((errno=ENOMEM));
@@ -79,10 +81,9 @@ int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) {
 	return 0;
 	return 0;
 }
 }
 
 
-
-
 int usbi_cond_init(usbi_cond_t *cond,
 int usbi_cond_init(usbi_cond_t *cond,
 				   const usbi_condattr_t *attr) {
 				   const usbi_condattr_t *attr) {
+	UNUSED(attr);
 	if(!cond)           return ((errno=EINVAL));
 	if(!cond)           return ((errno=EINVAL));
 	list_init(&cond->waiters    );
 	list_init(&cond->waiters    );
 	list_init(&cond->not_waiting);
 	list_init(&cond->not_waiting);
@@ -90,16 +91,14 @@ int usbi_cond_init(usbi_cond_t *cond,
 }
 }
 int usbi_cond_destroy(usbi_cond_t *cond) {
 int usbi_cond_destroy(usbi_cond_t *cond) {
 	// This assumes no one is using this anymore.  The check MAY NOT BE safe.
 	// This assumes no one is using this anymore.  The check MAY NOT BE safe.
-	struct usbi_cond_perthread *pos, *prev_pos = NULL;
+	struct usbi_cond_perthread *pos, *next_pos = NULL;
 	if(!cond) return ((errno=EINVAL));
 	if(!cond) return ((errno=EINVAL));
 	if(!list_empty(&cond->waiters)) return ((errno=EBUSY )); // (!see above!)
 	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_for_each_entry_safe(pos, next_pos, &cond->not_waiting, list, struct usbi_cond_perthread) {
 		CloseHandle(pos->event);
 		CloseHandle(pos->event);
 		list_del(&pos->list);
 		list_del(&pos->list);
-		prev_pos = pos;
+		free(pos);
 	}
 	}
-	free(prev_pos);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -129,7 +128,7 @@ int usbi_cond_signal(usbi_cond_t *cond) {
 	// The wait function will remove its respective item from the list.
 	// The wait function will remove its respective item from the list.
 	return SetEvent(pos->event) ? 0 : ((errno=EINVAL));
 	return SetEvent(pos->event) ? 0 : ((errno=EINVAL));
 }
 }
-static int __inline usbi_cond_intwait(usbi_cond_t *cond,
+__inline static int usbi_cond_intwait(usbi_cond_t *cond,
 									  usbi_mutex_t *mutex,
 									  usbi_mutex_t *mutex,
 									  DWORD timeout_ms) {
 									  DWORD timeout_ms) {
 	struct usbi_cond_perthread *pos;
 	struct usbi_cond_perthread *pos;
@@ -182,9 +181,11 @@ int usbi_cond_timedwait(usbi_cond_t *cond,
 	struct timeval targ_time, cur_time, delta_time;
 	struct timeval targ_time, cur_time, delta_time;
 	struct timespec cur_time_ns;
 	struct timespec cur_time_ns;
 	DWORD millis;
 	DWORD millis;
-	extern const uint64_t epoch_time;
 
 
-	GetSystemTimeAsFileTime(&filetime);
+	// GetSystemTimeAsFileTime() is not available on CE
+	SYSTEMTIME st;
+	GetSystemTime(&st);
+	SystemTimeToFileTime(&st, &filetime);
 	rtime.LowPart   = filetime.dwLowDateTime;
 	rtime.LowPart   = filetime.dwLowDateTime;
 	rtime.HighPart  = filetime.dwHighDateTime;
 	rtime.HighPart  = filetime.dwHighDateTime;
 	rtime.QuadPart -= epoch_time;
 	rtime.QuadPart -= epoch_time;
@@ -206,3 +207,6 @@ int usbi_cond_timedwait(usbi_cond_t *cond,
 	return usbi_cond_intwait(cond, mutex, millis);
 	return usbi_cond_intwait(cond, mutex, millis);
 }
 }
 
 
+int usbi_get_tid(void) {
+	return GetCurrentThreadId();
+}

+ 4 - 5
compat/libusb-1.0/libusb/os/threads_windows.h

@@ -1,7 +1,7 @@
 /*
 /*
- * libusb synchronization on Microsoft Windows
+ * libusbx synchronization on Microsoft Windows
  *
  *
- * Copyright (C) 2010 Michael Plante <michael.plante@gmail.com>
+ * Copyright © 2010 Michael Plante <michael.plante@gmail.com>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -21,8 +21,6 @@
 #ifndef LIBUSB_THREADS_WINDOWS_H
 #ifndef LIBUSB_THREADS_WINDOWS_H
 #define LIBUSB_THREADS_WINDOWS_H
 #define LIBUSB_THREADS_WINDOWS_H
 
 
-#include <windows.h>
-
 #define usbi_mutex_static_t     volatile LONG
 #define usbi_mutex_static_t     volatile LONG
 #define USBI_MUTEX_INITIALIZER  0
 #define USBI_MUTEX_INITIALIZER  0
 
 
@@ -84,5 +82,6 @@ int usbi_cond_timedwait(usbi_cond_t *cond,
 int usbi_cond_broadcast(usbi_cond_t *cond);
 int usbi_cond_broadcast(usbi_cond_t *cond);
 int usbi_cond_signal(usbi_cond_t *cond);
 int usbi_cond_signal(usbi_cond_t *cond);
 
 
-#endif /* LIBUSB_THREADS_WINDOWS_H */
+int usbi_get_tid(void);
 
 
+#endif /* LIBUSB_THREADS_WINDOWS_H */

+ 1026 - 0
compat/libusb-1.0/libusb/os/wince_usb.c

@@ -0,0 +1,1026 @@
+/*
+ * Windows CE backend for libusbx 1.0
+ * Copyright © 2011-2013 RealVNC Ltd.
+ * Large portions taken from Windows backend, which is
+ * Copyright © 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
+ */
+
+#include <libusbi.h>
+
+#include <stdint.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include "wince_usb.h"
+
+// Forward declares
+static int wince_clock_gettime(int clk_id, struct timespec *tp);
+unsigned __stdcall wince_clock_gettime_threaded(void* param);
+
+// Global variables
+uint64_t hires_frequency, hires_ticks_to_ps;
+int errno;
+const uint64_t epoch_time = UINT64_C(116444736000000000);       // 1970.01.01 00:00:000 in MS Filetime
+enum windows_version windows_version = WINDOWS_CE;
+static int concurrent_usage = -1;
+// 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;
+HANDLE driver_handle = INVALID_HANDLE_VALUE;
+
+/*
+ * Converts a windows error to human readable string
+ * uses retval as errorcode, or, if 0, use GetLastError()
+ */
+#if defined(ENABLE_LOGGING)
+static char* windows_error_str(uint32_t retval)
+{
+	static TCHAR wErr_string[ERR_BUFFER_SIZE];
+	static char err_string[ERR_BUFFER_SIZE];
+
+	DWORD size;
+	size_t i;
+	uint32_t error_code, format_error;
+
+	error_code = retval?retval:GetLastError();
+	
+	safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("[%d] "), error_code);
+	
+	size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code,
+		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &wErr_string[safe_tcslen(wErr_string)],
+		ERR_BUFFER_SIZE - (DWORD)safe_tcslen(wErr_string), NULL);
+	if (size == 0) {
+		format_error = GetLastError();
+		if (format_error)
+			safe_stprintf(wErr_string, ERR_BUFFER_SIZE,
+				_T("Windows error code %u (FormatMessage error code %u)"), error_code, format_error);
+		else
+			safe_stprintf(wErr_string, ERR_BUFFER_SIZE, _T("Unknown error code %u"), error_code);
+	} else {
+		// Remove CR/LF terminators
+		for (i=safe_tcslen(wErr_string)-1; ((wErr_string[i]==0x0A) || (wErr_string[i]==0x0D)); i--) {
+			wErr_string[i] = 0;
+		}
+	}
+	if (WideCharToMultiByte(CP_ACP, 0, wErr_string, -1, err_string, ERR_BUFFER_SIZE, NULL, NULL) < 0)
+	{
+		strcpy(err_string, "Unable to convert error string");
+	}
+	return err_string;
+}
+#endif
+
+static struct wince_device_priv *_device_priv(struct libusb_device *dev)
+{
+        return (struct wince_device_priv *) dev->os_priv;
+}
+
+// ceusbkwrapper to libusb error code mapping
+static int translate_driver_error(int error) 
+{
+	switch (error) {
+		case ERROR_INVALID_PARAMETER:
+			return LIBUSB_ERROR_INVALID_PARAM;
+		case ERROR_CALL_NOT_IMPLEMENTED:
+		case ERROR_NOT_SUPPORTED:
+			return LIBUSB_ERROR_NOT_SUPPORTED;
+		case ERROR_NOT_ENOUGH_MEMORY:
+			return LIBUSB_ERROR_NO_MEM;
+		case ERROR_INVALID_HANDLE:
+			return LIBUSB_ERROR_NO_DEVICE;
+		case ERROR_BUSY:
+			return LIBUSB_ERROR_BUSY;
+
+		// Error codes that are either unexpected, or have 
+		// no suitable LIBUSB_ERROR equivilant.
+		case ERROR_CANCELLED:
+		case ERROR_INTERNAL_ERROR:
+		default:
+			return LIBUSB_ERROR_OTHER;
+	}
+}
+
+static int init_dllimports()
+{
+	DLL_LOAD(ceusbkwrapper.dll, UkwOpenDriver, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceList, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwReleaseDeviceList, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceAddress, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwGetDeviceDescriptor, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwGetConfigDescriptor, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwCloseDriver, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwCancelTransfer, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwIssueControlTransfer, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwClaimInterface, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwReleaseInterface, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwSetInterfaceAlternateSetting, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwClearHaltHost, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwClearHaltDevice, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwGetConfig, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwSetConfig, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwResetDevice, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwKernelDriverActive, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwAttachKernelDriver, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwDetachKernelDriver, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwIssueBulkTransfer, TRUE);
+	DLL_LOAD(ceusbkwrapper.dll, UkwIsPipeHalted, TRUE);
+	return LIBUSB_SUCCESS;
+}
+
+static int init_device(struct libusb_device *dev, UKW_DEVICE drv_dev,
+					   unsigned char bus_addr, unsigned char dev_addr)
+{
+	struct wince_device_priv *priv = _device_priv(dev);
+	int r = LIBUSB_SUCCESS;
+
+	dev->bus_number = bus_addr;
+	dev->device_address = dev_addr;
+	priv->dev = drv_dev;
+
+	if (!UkwGetDeviceDescriptor(priv->dev, &(priv->desc))) {
+		r = translate_driver_error(GetLastError());
+	}
+	return r;
+}
+
+// Internal API functions
+static int wince_init(struct libusb_context *ctx)
+{
+	int i, r = LIBUSB_ERROR_OTHER;
+	HANDLE semaphore;
+	TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
+
+	_stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
+	semaphore = CreateSemaphore(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?
+		// Initialize pollable file descriptors
+		init_polling();
+
+		// Load DLL imports
+		if (init_dllimports() != LIBUSB_SUCCESS) {
+			usbi_err(ctx, "could not resolve DLL functions");
+			r = LIBUSB_ERROR_NOT_SUPPORTED;
+			goto init_exit;
+		}
+
+		// try to open a handle to the driver
+		driver_handle = UkwOpenDriver();
+		if (driver_handle == INVALID_HANDLE_VALUE) {
+			usbi_err(ctx, "could not connect to driver");
+			r = LIBUSB_ERROR_NOT_SUPPORTED;
+			goto init_exit;
+		}
+
+		// Windows CE doesn't have a way of specifying thread affinity, so this code
+		// just has  to hope QueryPerformanceCounter doesn't report different values when
+		// running on different cores.
+		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 = CreateThread(NULL, 0, wince_clock_gettime_threaded, NULL, 0, NULL);
+		if (timer_thread == NULL) {
+			usbi_err(ctx, "Unable to create timer thread - aborting");
+			goto init_exit;
+		}
+
+		// Wait for timer thread to init before continuing.
+		if (WaitForSingleObject(timer_response, INFINITE) != WAIT_OBJECT_0) {
+			usbi_err(ctx, "Failed to wait for timer thread to become ready - aborting");
+			goto init_exit;
+		}
+	}
+	// 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 (driver_handle != INVALID_HANDLE_VALUE) {
+			UkwCloseDriver(driver_handle);
+			driver_handle = INVALID_HANDLE_VALUE;
+		}
+		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;
+		}
+	}
+
+	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;
+}
+
+static void wince_exit(void)
+{
+	int i;
+	HANDLE semaphore;
+	TCHAR sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID)
+
+	_stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)GetCurrentProcessId()&0xFFFFFFFF);
+	semaphore = CreateSemaphore(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
+		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;
+		}
+		if (driver_handle != INVALID_HANDLE_VALUE) {
+			UkwCloseDriver(driver_handle);
+			driver_handle = INVALID_HANDLE_VALUE;
+		}
+	}
+
+	ReleaseSemaphore(semaphore, 1, NULL);	// increase count back to 1
+	CloseHandle(semaphore);
+}
+
+static int wince_get_device_list(
+	struct libusb_context *ctx,
+	struct discovered_devs **discdevs)
+{
+	UKW_DEVICE devices[MAX_DEVICE_COUNT];
+	struct discovered_devs * new_devices = *discdevs;
+	DWORD count = 0, i;
+	struct libusb_device *dev = NULL;
+	unsigned char bus_addr, dev_addr;
+	unsigned long session_id;
+	BOOL success;
+	DWORD release_list_offset = 0;
+	int r = LIBUSB_SUCCESS;
+
+	success = UkwGetDeviceList(driver_handle, devices, MAX_DEVICE_COUNT, &count);
+	if (!success) {
+		int libusbErr = translate_driver_error(GetLastError());
+		usbi_err(ctx, "could not get devices: %s", windows_error_str(0));
+		return libusbErr;
+	}
+	for(i = 0; i < count; ++i) {
+		release_list_offset = i;
+		success = UkwGetDeviceAddress(devices[i], &bus_addr, &dev_addr, &session_id);
+		if (!success) {
+			r = translate_driver_error(GetLastError());
+			usbi_err(ctx, "could not get device address for %d: %s", i, windows_error_str(0));
+			goto err_out;
+		}
+		dev = usbi_get_device_by_session_id(ctx, session_id);
+		if (dev) {
+			usbi_dbg("using existing device for %d/%d (session %ld)",
+					bus_addr, dev_addr, session_id);
+			libusb_ref_device(dev);
+			// Release just this element in the device list (as we already hold a 
+			// reference to it).
+			UkwReleaseDeviceList(driver_handle, &devices[i], 1);
+			release_list_offset++;
+		} else {
+			usbi_dbg("allocating new device for %d/%d (session %ld)",
+					bus_addr, dev_addr, session_id);
+			dev = usbi_alloc_device(ctx, session_id);
+			if (!dev) {
+				r = LIBUSB_ERROR_NO_MEM;
+				goto err_out;
+			}
+			r = init_device(dev, devices[i], bus_addr, dev_addr);
+			if (r < 0)
+				goto err_out;
+			r = usbi_sanitize_device(dev);
+			if (r < 0)
+				goto err_out;
+		}
+		new_devices = discovered_devs_append(new_devices, dev);
+		if (!discdevs) {
+			r = LIBUSB_ERROR_NO_MEM;
+			goto err_out;
+		}
+		safe_unref_device(dev);
+	}
+	*discdevs = new_devices;
+	return r;
+err_out:
+	*discdevs = new_devices;
+	safe_unref_device(dev);
+	// Release the remainder of the unprocessed device list.
+	// The devices added to new_devices already will still be passed up to libusb, 
+	// which can dispose of them at its leisure.
+	UkwReleaseDeviceList(driver_handle, &devices[release_list_offset], count - release_list_offset);
+	return r;
+}
+
+static int wince_open(struct libusb_device_handle *handle)
+{
+	// Nothing to do to open devices as a handle to it has
+	// been retrieved by wince_get_device_list
+	return LIBUSB_SUCCESS;
+}
+
+static void wince_close(struct libusb_device_handle *handle)
+{
+	// Nothing to do as wince_open does nothing.
+}
+
+static int wince_get_device_descriptor(
+   struct libusb_device *device,
+   unsigned char *buffer, int *host_endian)
+{
+	struct wince_device_priv *priv = _device_priv(device);
+
+	*host_endian = 1;
+	memcpy(buffer, &priv->desc, DEVICE_DESC_LENGTH);
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_get_active_config_descriptor(
+	struct libusb_device *device,
+	unsigned char *buffer, size_t len, int *host_endian)
+{
+	struct wince_device_priv *priv = _device_priv(device);
+	DWORD actualSize = len;
+	*host_endian = 0;
+	if (!UkwGetConfigDescriptor(priv->dev, UKW_ACTIVE_CONFIGURATION, buffer, len, &actualSize)) {
+		return translate_driver_error(GetLastError());
+	}
+	return actualSize;
+}
+
+static int wince_get_config_descriptor(
+	struct libusb_device *device,
+	uint8_t config_index,
+	unsigned char *buffer, size_t len, int *host_endian)
+{
+	struct wince_device_priv *priv = _device_priv(device);
+	DWORD actualSize = len;
+	*host_endian = 0;
+	if (!UkwGetConfigDescriptor(priv->dev, config_index, buffer, len, &actualSize)) {
+		return translate_driver_error(GetLastError());
+	}
+	return actualSize;
+}
+
+static int wince_get_configuration(
+   struct libusb_device_handle *handle,
+   int *config)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	UCHAR cv = 0;
+	if (!UkwGetConfig(priv->dev, &cv)) {
+		return translate_driver_error(GetLastError());
+	}
+	(*config) = cv;
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_set_configuration(
+	struct libusb_device_handle *handle,
+	int config)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	// Setting configuration 0 places the device in Address state.
+	// This should correspond to the "unconfigured state" required by
+	// libusb when the specified configuration is -1.
+	UCHAR cv = (config < 0) ? 0 : config;
+	if (!UkwSetConfig(priv->dev, cv)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_claim_interface(
+	struct libusb_device_handle *handle,
+	int interface_number)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwClaimInterface(priv->dev, interface_number)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_release_interface(
+	struct libusb_device_handle *handle,
+	int interface_number)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, 0)) {
+		return translate_driver_error(GetLastError());
+	}
+	if (!UkwReleaseInterface(priv->dev, interface_number)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_set_interface_altsetting(
+	struct libusb_device_handle *handle,
+	int interface_number, int altsetting)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, altsetting)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_clear_halt(
+	struct libusb_device_handle *handle,
+	unsigned char endpoint)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwClearHaltHost(priv->dev, endpoint)) {
+		return translate_driver_error(GetLastError());
+	}
+	if (!UkwClearHaltDevice(priv->dev, endpoint)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_reset_device(
+	struct libusb_device_handle *handle)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwResetDevice(priv->dev)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_kernel_driver_active(
+	struct libusb_device_handle *handle,
+	int interface_number)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	BOOL result = FALSE;
+	if (!UkwKernelDriverActive(priv->dev, interface_number, &result)) {
+		return translate_driver_error(GetLastError());
+	}
+	return result ? 1 : 0;
+}
+
+static int wince_detach_kernel_driver(
+	struct libusb_device_handle *handle,
+	int interface_number)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwDetachKernelDriver(priv->dev, interface_number)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_attach_kernel_driver(
+	struct libusb_device_handle *handle,
+	int interface_number)
+{
+	struct wince_device_priv *priv = _device_priv(handle->dev);
+	if (!UkwAttachKernelDriver(priv->dev, interface_number)) {
+		return translate_driver_error(GetLastError());
+	}	
+	return LIBUSB_SUCCESS;
+}
+
+static void wince_destroy_device(
+	struct libusb_device *dev)
+{
+	struct wince_device_priv *priv = _device_priv(dev);
+	UkwReleaseDeviceList(driver_handle, &priv->dev, 1);
+}
+
+static void wince_clear_transfer_priv(
+	struct usbi_transfer *itransfer)
+{
+	struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
+	struct winfd wfd = fd_to_winfd(transfer_priv->pollable_fd.fd);
+	// No need to cancel transfer as it is either complete or abandoned
+	wfd.itransfer = NULL;
+	CloseHandle(wfd.handle);
+	usbi_free_fd(&transfer_priv->pollable_fd);
+}
+
+static int wince_cancel_transfer(
+	struct usbi_transfer *itransfer)
+{
+	struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+	struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+	struct wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
+	
+	if (!UkwCancelTransfer(priv->dev, transfer_priv->pollable_fd.overlapped, UKW_TF_NO_WAIT)) {
+		return translate_driver_error(GetLastError());
+	}
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_submit_control_or_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 wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
+	struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+	BOOL direction_in, ret;
+	struct winfd wfd;
+	DWORD flags;
+	HANDLE eventHandle;
+	PUKW_CONTROL_HEADER setup = NULL;
+	const BOOL control_transfer = transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL;
+
+	transfer_priv->pollable_fd = INVALID_WINFD;
+	if (control_transfer) {
+		setup = (PUKW_CONTROL_HEADER) transfer->buffer;
+		direction_in = setup->bmRequestType & LIBUSB_ENDPOINT_IN;
+	} else {
+		direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
+	}
+	flags = direction_in ? UKW_TF_IN_TRANSFER : UKW_TF_OUT_TRANSFER;
+	flags |= UKW_TF_SHORT_TRANSFER_OK;
+
+	eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
+	if (eventHandle == NULL) {
+		usbi_err(ctx, "Failed to create event for async transfer");
+		return LIBUSB_ERROR_NO_MEM;
+	}
+
+	wfd = usbi_create_fd(eventHandle, direction_in ? RW_READ : RW_WRITE, itransfer, &wince_cancel_transfer);
+	if (wfd.fd < 0) {
+		CloseHandle(eventHandle);
+		return LIBUSB_ERROR_NO_MEM;
+	}
+
+	transfer_priv->pollable_fd = wfd;
+	if (control_transfer) {
+		// Split out control setup header and data buffer
+		DWORD bufLen = transfer->length - sizeof(UKW_CONTROL_HEADER);
+		PVOID buf = (PVOID) &transfer->buffer[sizeof(UKW_CONTROL_HEADER)];
+
+		ret = UkwIssueControlTransfer(priv->dev, flags, setup, buf, bufLen, &transfer->actual_length, wfd.overlapped);
+	} else {
+		ret = UkwIssueBulkTransfer(priv->dev, flags, transfer->endpoint, transfer->buffer, 
+			transfer->length, &transfer->actual_length, wfd.overlapped);
+	}
+	if (!ret) {
+		int libusbErr = translate_driver_error(GetLastError());
+		usbi_err(ctx, "UkwIssue%sTransfer failed: error %d",
+			control_transfer ? "Control" : "Bulk", GetLastError());
+		wince_clear_transfer_priv(itransfer);
+		return libusbErr;
+	}
+	usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? POLLIN : POLLOUT);
+	itransfer->flags |= USBI_TRANSFER_UPDATED_FDS;
+
+	return LIBUSB_SUCCESS;
+}
+
+static int wince_submit_iso_transfer(struct usbi_transfer *itransfer)
+{
+	return LIBUSB_ERROR_NOT_SUPPORTED;
+}
+
+static int wince_submit_transfer(
+	struct usbi_transfer *itransfer)
+{
+	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:
+		return wince_submit_control_or_bulk_transfer(itransfer);
+	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+		return wince_submit_iso_transfer(itransfer);
+	default:
+		usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
+		return LIBUSB_ERROR_INVALID_PARAM;
+	}
+}
+
+static void wince_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 wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
+	struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
+	int status;
+
+	usbi_dbg("handling I/O completion with errcode %d", io_result);
+
+	if (io_result == ERROR_NOT_SUPPORTED && 
+		transfer->type != LIBUSB_TRANSFER_TYPE_CONTROL) {
+		/* For functional stalls, the WinCE USB layer (and therefore the USB Kernel Wrapper 
+		 * Driver) will report USB_ERROR_STALL/ERROR_NOT_SUPPORTED in situations where the 
+		 * endpoint isn't actually stalled.
+		 *
+		 * One example of this is that some devices will occasionally fail to reply to an IN
+		 * token. The WinCE USB layer carries on with the transaction until it is completed
+		 * (or cancelled) but then completes it with USB_ERROR_STALL.
+		 *
+		 * This code therefore needs to confirm that there really is a stall error, by both
+		 * checking the pipe status and requesting the endpoint status from the device.
+		 */
+		BOOL halted = FALSE;
+		usbi_dbg("checking I/O completion with errcode ERROR_NOT_SUPPORTED is really a stall");
+		if (UkwIsPipeHalted(priv->dev, transfer->endpoint, &halted)) {
+			/* Pipe status retrieved, so now request endpoint status by sending a GET_STATUS
+			 * control request to the device. This is done synchronously, which is a bit 
+			 * naughty, but this is a special corner case.
+			 */
+			WORD wStatus = 0;
+			DWORD written = 0;
+			UKW_CONTROL_HEADER ctrlHeader;
+			ctrlHeader.bmRequestType = LIBUSB_REQUEST_TYPE_STANDARD |
+				LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_ENDPOINT;
+			ctrlHeader.bRequest = LIBUSB_REQUEST_GET_STATUS;
+			ctrlHeader.wValue = 0;
+			ctrlHeader.wIndex = transfer->endpoint;
+			ctrlHeader.wLength = sizeof(wStatus);
+			if (UkwIssueControlTransfer(priv->dev,
+					UKW_TF_IN_TRANSFER | UKW_TF_SEND_TO_ENDPOINT,
+					&ctrlHeader, &wStatus, sizeof(wStatus), &written, NULL)) {
+				if (written == sizeof(wStatus) &&
+						(wStatus & STATUS_HALT_FLAG) == 0) {
+					if (!halted || UkwClearHaltHost(priv->dev, transfer->endpoint)) {
+						usbi_dbg("Endpoint doesn't appear to be stalled, overriding error with success");
+						io_result = ERROR_SUCCESS;
+					} else {
+						usbi_dbg("Endpoint doesn't appear to be stalled, but the host is halted, changing error");
+						io_result = ERROR_IO_DEVICE;
+					}
+				}
+			}
+		}
+	}
+
+	switch(io_result) {
+	case ERROR_SUCCESS:
+		itransfer->transferred += io_size;
+		status = LIBUSB_TRANSFER_COMPLETED;
+		break;
+	case ERROR_CANCELLED:
+		usbi_dbg("detected transfer cancel");
+		status = LIBUSB_TRANSFER_CANCELLED;
+		break;
+	case ERROR_NOT_SUPPORTED:
+	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(io_result));
+		status = LIBUSB_TRANSFER_ERROR;
+		break;
+	}
+	wince_clear_transfer_priv(itransfer);
+	if (status == LIBUSB_TRANSFER_CANCELLED) {
+		usbi_handle_transfer_cancellation(itransfer);
+	} else {
+		usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
+	}
+}
+
+static void wince_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:
+		wince_transfer_callback (itransfer, io_result, io_size);
+		break;
+	default:
+		usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
+	}
+}
+
+static int wince_handle_events(
+	struct libusb_context *ctx,
+	struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
+{
+	struct wince_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 && HasOverlappedIoCompleted(transfer_priv->pollable_fd.overlapped)) {
+			io_result = (DWORD)transfer_priv->pollable_fd.overlapped->Internal;
+			io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh;
+			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.
+			wince_handle_callback(transfer, io_result, io_size);
+		} else if (found) {
+			usbi_err(ctx, "matching transfer for fd %x has not completed", fds[i]);
+			return LIBUSB_ERROR_OTHER;
+		} 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 wince_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);
+	}
+
+	// Signal wince_init() that we're ready to service requests
+	if (ReleaseSemaphore(timer_response, 1, NULL) == 0) {
+		usbi_dbg("unable to release timer semaphore: %s", windows_error_str(0));
+	}
+
+	// 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.
+				wince_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: %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 wince_clock_gettime(int clk_id, struct timespec *tp)
+{
+	FILETIME filetime;
+	ULARGE_INTEGER rtime;
+	DWORD r;
+	SYSTEMTIME st;
+	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)
+		GetSystemTime(&st);
+		SystemTimeToFileTime(&st, &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;
+	}
+}
+
+const struct usbi_os_backend wince_backend = {
+        "Windows CE",
+        0,
+        wince_init,
+        wince_exit,
+
+        wince_get_device_list,
+	NULL,				/* hotplug_poll */
+        wince_open,
+        wince_close,
+
+        wince_get_device_descriptor,
+        wince_get_active_config_descriptor,
+        wince_get_config_descriptor,
+	NULL,				/* get_config_descriptor_by_value() */
+
+        wince_get_configuration,
+        wince_set_configuration,
+        wince_claim_interface,
+        wince_release_interface,
+
+        wince_set_interface_altsetting,
+        wince_clear_halt,
+        wince_reset_device,
+
+        wince_kernel_driver_active,
+        wince_detach_kernel_driver,
+        wince_attach_kernel_driver,
+
+        wince_destroy_device,
+
+        wince_submit_transfer,
+        wince_cancel_transfer,
+        wince_clear_transfer_priv,
+
+        wince_handle_events,
+
+        wince_clock_gettime,
+        sizeof(struct wince_device_priv),
+        sizeof(struct wince_device_handle_priv),
+        sizeof(struct wince_transfer_priv),
+        0,
+};

+ 131 - 0
compat/libusb-1.0/libusb/os/wince_usb.h

@@ -0,0 +1,131 @@
+/*
+ * Windows CE backend for libusbx 1.0
+ * Copyright © 2011-2013 RealVNC Ltd.
+ * Portions taken from Windows backend, which is
+ * Copyright © 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
+
+#include "windows_common.h"
+
+#include <windows.h>
+#include "poll_windows.h"
+
+#define MAX_DEVICE_COUNT            256
+
+// This is a modified dump of the types in the ceusbkwrapper.h library header
+// with functions transformed into extern pointers.
+//
+// This backend dynamically loads ceusbkwrapper.dll and doesn't include
+// ceusbkwrapper.h directly to simplify the build process. The kernel
+// side wrapper driver is built using the platform image build tools,
+// which makes it difficult to reference directly from the libusbx build
+// system.
+struct UKW_DEVICE_PRIV;
+typedef struct UKW_DEVICE_PRIV *UKW_DEVICE;
+typedef UKW_DEVICE *PUKW_DEVICE, *LPUKW_DEVICE;
+
+typedef struct {
+	UINT8 bLength;
+	UINT8 bDescriptorType;
+	UINT16 bcdUSB;
+	UINT8 bDeviceClass;
+	UINT8 bDeviceSubClass;
+	UINT8 bDeviceProtocol;
+	UINT8 bMaxPacketSize0;
+	UINT16 idVendor;
+	UINT16 idProduct;
+	UINT16 bcdDevice;
+	UINT8 iManufacturer;
+	UINT8 iProduct;
+	UINT8 iSerialNumber;
+	UINT8 bNumConfigurations;
+} UKW_DEVICE_DESCRIPTOR, *PUKW_DEVICE_DESCRIPTOR, *LPUKW_DEVICE_DESCRIPTOR;
+
+typedef struct {
+	UINT8 bmRequestType;
+	UINT8 bRequest;
+	UINT16 wValue;
+	UINT16 wIndex;
+	UINT16 wLength;
+} UKW_CONTROL_HEADER, *PUKW_CONTROL_HEADER, *LPUKW_CONTROL_HEADER;
+
+// Collection of flags which can be used when issuing transfer requests
+/* Indicates that the transfer direction is 'in' */
+#define UKW_TF_IN_TRANSFER        0x00000001
+/* Indicates that the transfer direction is 'out' */
+#define UKW_TF_OUT_TRANSFER       0x00000000
+/* Specifies that the transfer should complete as soon as possible,
+ * even if no OVERLAPPED structure has been provided. */
+#define UKW_TF_NO_WAIT            0x00000100
+/* Indicates that transfers shorter than the buffer are ok */
+#define UKW_TF_SHORT_TRANSFER_OK  0x00000200
+#define UKW_TF_SEND_TO_DEVICE     0x00010000
+#define UKW_TF_SEND_TO_INTERFACE  0x00020000
+#define UKW_TF_SEND_TO_ENDPOINT   0x00040000
+/* Don't block when waiting for memory allocations */
+#define UKW_TF_DONT_BLOCK_FOR_MEM 0x00080000
+
+/* Value to use when dealing with configuration values, such as UkwGetConfigDescriptor, 
+ * to specify the currently active configuration for the device. */
+#define UKW_ACTIVE_CONFIGURATION -1
+
+DLL_DECLARE(WINAPI, HANDLE, UkwOpenDriver, ());
+DLL_DECLARE(WINAPI, BOOL, UkwGetDeviceList, (HANDLE, LPUKW_DEVICE, DWORD, LPDWORD));
+DLL_DECLARE(WINAPI, void, UkwReleaseDeviceList, (HANDLE, LPUKW_DEVICE, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwGetDeviceAddress, (UKW_DEVICE, unsigned char*, unsigned char*, unsigned long*));
+DLL_DECLARE(WINAPI, BOOL, UkwGetDeviceDescriptor, (UKW_DEVICE, LPUKW_DEVICE_DESCRIPTOR));
+DLL_DECLARE(WINAPI, BOOL, UkwGetConfigDescriptor, (UKW_DEVICE, DWORD, LPVOID, DWORD, LPDWORD));
+DLL_DECLARE(WINAPI, void, UkwCloseDriver, (HANDLE));
+DLL_DECLARE(WINAPI, BOOL, UkwCancelTransfer, (UKW_DEVICE, LPOVERLAPPED, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwIssueControlTransfer, (UKW_DEVICE, DWORD, LPUKW_CONTROL_HEADER, LPVOID, DWORD, LPDWORD, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, UkwClaimInterface, (UKW_DEVICE, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwReleaseInterface, (UKW_DEVICE, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwSetInterfaceAlternateSetting, (UKW_DEVICE, DWORD, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwClearHaltHost, (UKW_DEVICE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, UkwClearHaltDevice, (UKW_DEVICE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, UkwGetConfig, (UKW_DEVICE, PUCHAR));
+DLL_DECLARE(WINAPI, BOOL, UkwSetConfig, (UKW_DEVICE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, UkwResetDevice, (UKW_DEVICE));
+DLL_DECLARE(WINAPI, BOOL, UkwKernelDriverActive, (UKW_DEVICE, DWORD, PBOOL));
+DLL_DECLARE(WINAPI, BOOL, UkwAttachKernelDriver, (UKW_DEVICE, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwDetachKernelDriver, (UKW_DEVICE, DWORD));
+DLL_DECLARE(WINAPI, BOOL, UkwIssueBulkTransfer, (UKW_DEVICE, DWORD, UCHAR, LPVOID, DWORD, LPDWORD, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, UkwIsPipeHalted, (UKW_DEVICE, UCHAR, LPBOOL));
+
+// Used to determine if an endpoint status really is halted on a failed transfer.
+#define STATUS_HALT_FLAG 0x1
+
+struct wince_device_priv {
+	UKW_DEVICE dev;
+	UKW_DEVICE_DESCRIPTOR desc;
+};
+
+struct wince_device_handle_priv {
+	// This member isn't used, but only exists to avoid an empty structure
+	// for private data for the device handle.
+	int reserved;
+};
+
+struct wince_transfer_priv {
+	struct winfd pollable_fd;
+	uint8_t interface_number;
+};
+

+ 108 - 0
compat/libusb-1.0/libusb/os/windows_common.h

@@ -0,0 +1,108 @@
+/*
+ * Windows backend common header for libusbx 1.0
+ *
+ * This file brings together header code common between
+ * the desktop Windows and Windows CE backends.
+ * Copyright © 2012-2013 RealVNC Ltd.
+ * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
+ * 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
+
+// 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
+
+#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_stricmp(str1, str2) _stricmp(((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(dst, count, ...) do {_snprintf(dst, count, __VA_ARGS__); (dst)[(count)-1] = 0; } while(0)
+#define safe_stprintf _sntprintf
+#define safe_tcslen(str) ((str==NULL)?0:_tcslen(str))
+#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)
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+#define ERR_BUFFER_SIZE             256
+#define TIMER_REQUEST_RETRY_MS      100
+#define MAX_TIMER_SEMAPHORES        128
+
+
+/*
+ * 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
+
+#ifndef _WIN32_WCE
+#define DLL_STRINGIFY(dll) #dll
+#define DLL_GET_MODULE_HANDLE(dll) GetModuleHandleA(DLL_STRINGIFY(dll))
+#define DLL_LOAD_LIBRARY(dll) LoadLibraryA(DLL_STRINGIFY(dll))
+#else
+#define DLL_STRINGIFY(dll) L#dll
+#define DLL_GET_MODULE_HANDLE(dll) GetModuleHandle(DLL_STRINGIFY(dll))
+#define DLL_LOAD_LIBRARY(dll) LoadLibrary(DLL_STRINGIFY(dll))
+#endif
+
+#define DLL_LOAD_PREFIXNAME(dll, prefixname, name, ret_on_failure) \
+	do {                                                           \
+		HMODULE h = DLL_GET_MODULE_HANDLE(dll);                    \
+	if (!h)                                                        \
+		h = DLL_LOAD_LIBRARY(dll);                                 \
+	if (!h) {                                                      \
+		if (ret_on_failure) { return LIBUSB_ERROR_NOT_FOUND; }     \
+		else { break; }                                            \
+	}                                                              \
+	prefixname = (__dll_##name##_t)GetProcAddress(h,               \
+	                        DLL_STRINGIFY(name));                  \
+	if (prefixname) break;                                         \
+	prefixname = (__dll_##name##_t)GetProcAddress(h,               \
+	                        DLL_STRINGIFY(name) DLL_STRINGIFY(A)); \
+	if (prefixname) break;                                         \
+	prefixname = (__dll_##name##_t)GetProcAddress(h,               \
+	                        DLL_STRINGIFY(name) DLL_STRINGIFY(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)

File diff suppressed because it is too large
+ 323 - 150
compat/libusb-1.0/libusb/os/windows_usb.c


+ 421 - 111
compat/libusb-1.0/libusb/os/windows_usb.h

@@ -1,6 +1,6 @@
 /*
 /*
- * Windows backend for libusb 1.0
- * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com>
+ * Windows backend for libusbx 1.0
+ * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
  * With contributions from Michael Plante, Orin Eman et al.
  * With contributions from Michael Plante, Orin Eman et al.
  * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
  * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
  * Major code testing contribution by Xiaofan Chen
  * Major code testing contribution by Xiaofan Chen
@@ -22,6 +22,8 @@
 
 
 #pragma once
 #pragma once
 
 
+#include "windows_common.h"
+
 #if defined(_MSC_VER)
 #if defined(_MSC_VER)
 // disable /W4 MSVC warnings that are benign
 // disable /W4 MSVC warnings that are benign
 #pragma warning(disable:4127) // conditional expression is constant
 #pragma warning(disable:4127) // conditional expression is constant
@@ -30,17 +32,6 @@
 #pragma warning(disable:4201) // nameless struct/union
 #pragma warning(disable:4201) // nameless struct/union
 #endif
 #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
 // Missing from MSVC6 setupapi.h
 #if !defined(SPDRP_ADDRESS)
 #if !defined(SPDRP_ADDRESS)
 #define SPDRP_ADDRESS	28
 #define SPDRP_ADDRESS	28
@@ -50,45 +41,30 @@
 #endif
 #endif
 
 
 #if defined(__CYGWIN__ )
 #if defined(__CYGWIN__ )
+#define _stricmp stricmp
 // cygwin produces a warning unless these prototypes are defined
 // cygwin produces a warning unless these prototypes are defined
 extern int _snprintf(char *buffer, size_t count, const char *format, ...);
 extern int _snprintf(char *buffer, size_t count, const char *format, ...);
 extern char *_strdup(const char *strSource);
 extern char *_strdup(const char *strSource);
 // _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread
 // _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)
 #define _beginthreadex(a, b, c, d, e, f) CreateThread(a, b, (LPTHREAD_START_ROUTINE)c, d, e, f)
 #endif
 #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_CTRL_BUFFER_LENGTH      4096
 #define MAX_USB_DEVICES             256
 #define MAX_USB_DEVICES             256
 #define MAX_USB_STRING_LENGTH       128
 #define MAX_USB_STRING_LENGTH       128
+#define MAX_HID_REPORT_SIZE         1024
+#define MAX_HID_DESCRIPTOR_SIZE     256
 #define MAX_GUID_STRING_LENGTH      40
 #define MAX_GUID_STRING_LENGTH      40
 #define MAX_PATH_LENGTH             128
 #define MAX_PATH_LENGTH             128
 #define MAX_KEY_LENGTH              256
 #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 LIST_SEPARATOR              ';'
 #define HTAB_SIZE                   1021
 #define HTAB_SIZE                   1021
 
 
+// Handle code for HID interface that have been claimed ("dibs")
+#define INTERFACE_CLAIMED           ((HANDLE)(intptr_t)0xD1B5)
+// Additional return code for HID operations that completed synchronously
+#define LIBUSB_COMPLETED            (LIBUSB_SUCCESS + 1)
+
 // http://msdn.microsoft.com/en-us/library/ff545978.aspx
 // http://msdn.microsoft.com/en-us/library/ff545978.aspx
 // http://msdn.microsoft.com/en-us/library/ff545972.aspx
 // http://msdn.microsoft.com/en-us/library/ff545972.aspx
 // http://msdn.microsoft.com/en-us/library/ff545982.aspx
 // http://msdn.microsoft.com/en-us/library/ff545982.aspx
@@ -101,7 +77,9 @@ const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0
 #if !defined(GUID_DEVINTERFACE_USB_HUB)
 #if !defined(GUID_DEVINTERFACE_USB_HUB)
 const GUID GUID_DEVINTERFACE_USB_HUB = { 0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8} };
 const GUID GUID_DEVINTERFACE_USB_HUB = { 0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8} };
 #endif
 #endif
-const GUID GUID_NULL = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} };
+#if !defined(GUID_DEVINTERFACE_LIBUSB0_FILTER)
+const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9} };
+#endif
 
 
 
 
 /*
 /*
@@ -110,34 +88,43 @@ const GUID GUID_NULL = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x
 #define USB_API_UNSUPPORTED 0
 #define USB_API_UNSUPPORTED 0
 #define USB_API_HUB         1
 #define USB_API_HUB         1
 #define USB_API_COMPOSITE   2
 #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} };
+#define USB_API_WINUSBX     3
+#define USB_API_HID         4
+#define USB_API_MAX         5
+// The following is used to indicate if the HID or composite extra props have already been set.
+#define USB_API_SET         (1<<USB_API_MAX) 
+
+// Sub-APIs for WinUSB-like driver APIs (WinUSB, libusbK, libusb-win32 through the libusbK DLL)
+// Must have the same values as the KUSB_DRVID enum from libusbk.h
+#define SUB_API_NOTSET      -1
+#define SUB_API_LIBUSBK     0
+#define SUB_API_LIBUSB0     1
+#define SUB_API_WINUSB      2
+#define SUB_API_MAX         3
+
+#define WINUSBX_DRV_NAMES   { "libusbK", "libusb0", "WinUSB"}
 
 
 struct windows_usb_api_backend {
 struct windows_usb_api_backend {
 	const uint8_t id;
 	const uint8_t id;
 	const char* designation;
 	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 char **driver_name_list; // Driver name, without .sys, e.g. "usbccgp"
 	const uint8_t nb_driver_names;
 	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);
+	int (*init)(int sub_api, struct libusb_context *ctx);
+	int (*exit)(int sub_api);
+	int (*open)(int sub_api, struct libusb_device_handle *dev_handle);
+	void (*close)(int sub_api, struct libusb_device_handle *dev_handle);
+	int (*configure_endpoints)(int sub_api, struct libusb_device_handle *dev_handle, int iface);
+	int (*claim_interface)(int sub_api, struct libusb_device_handle *dev_handle, int iface);
+	int (*set_interface_altsetting)(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting);
+	int (*release_interface)(int sub_api, struct libusb_device_handle *dev_handle, int iface);
+	int (*clear_halt)(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
+	int (*reset_device)(int sub_api, struct libusb_device_handle *dev_handle);
+	int (*submit_bulk_transfer)(int sub_api, struct usbi_transfer *itransfer);
+	int (*submit_iso_transfer)(int sub_api, struct usbi_transfer *itransfer);
+	int (*submit_control_transfer)(int sub_api, struct usbi_transfer *itransfer);
+	int (*abort_control)(int sub_api, struct usbi_transfer *itransfer);
+	int (*abort_transfers)(int sub_api, struct usbi_transfer *itransfer);
+	int (*copy_transfer_data)(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
 };
 };
 
 
 extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX];
 extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX];
@@ -151,21 +138,90 @@ extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX];
  * private structures definition
  * private structures definition
  * with inline pseudo constructors/destructors
  * with inline pseudo constructors/destructors
  */
  */
+
+// TODO (v2+): move hid desc to libusb.h?
+struct libusb_hid_descriptor {
+	uint8_t  bLength;
+	uint8_t  bDescriptorType;
+	uint16_t bcdHID;
+	uint8_t  bCountryCode;
+	uint8_t  bNumDescriptors;
+	uint8_t  bClassDescriptorType;
+	uint16_t wClassDescriptorLength;
+};
+#define LIBUSB_DT_HID_SIZE              9
+#define HID_MAX_CONFIG_DESC_SIZE (LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE \
+	+ LIBUSB_DT_HID_SIZE + 2 * LIBUSB_DT_ENDPOINT_SIZE)
+#define HID_MAX_REPORT_SIZE             1024
+#define HID_IN_EP                       0x81
+#define HID_OUT_EP                      0x02
+#define LIBUSB_REQ_RECIPIENT(request_type) ((request_type) & 0x1F)
+#define LIBUSB_REQ_TYPE(request_type) ((request_type) & (0x03 << 5))
+#define LIBUSB_REQ_IN(request_type) ((request_type) & LIBUSB_ENDPOINT_IN)
+#define LIBUSB_REQ_OUT(request_type) (!LIBUSB_REQ_IN(request_type))
+
+// The following are used for HID reports IOCTLs
+#define HID_CTL_CODE(id) \
+  CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_NEITHER, FILE_ANY_ACCESS)
+#define HID_BUFFER_CTL_CODE(id) \
+  CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HID_IN_CTL_CODE(id) \
+  CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+#define HID_OUT_CTL_CODE(id) \
+  CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+
+#define IOCTL_HID_GET_FEATURE                 HID_OUT_CTL_CODE(100)
+#define IOCTL_HID_GET_INPUT_REPORT            HID_OUT_CTL_CODE(104)
+#define IOCTL_HID_SET_FEATURE                 HID_IN_CTL_CODE(100)
+#define IOCTL_HID_SET_OUTPUT_REPORT           HID_IN_CTL_CODE(101)
+
+enum libusb_hid_request_type {
+	HID_REQ_GET_REPORT = 0x01,
+	HID_REQ_GET_IDLE = 0x02,
+	HID_REQ_GET_PROTOCOL = 0x03,
+	HID_REQ_SET_REPORT = 0x09,
+	HID_REQ_SET_IDLE = 0x0A,
+	HID_REQ_SET_PROTOCOL = 0x0B
+};
+
+enum libusb_hid_report_type {
+	HID_REPORT_TYPE_INPUT = 0x01,
+	HID_REPORT_TYPE_OUTPUT = 0x02,
+	HID_REPORT_TYPE_FEATURE = 0x03
+};
+
+struct hid_device_priv {
+	uint16_t vid;
+	uint16_t pid;
+	uint8_t config;
+	uint8_t nb_interfaces;
+	bool uses_report_ids[3];	// input, ouptput, feature
+	uint16_t input_report_size;
+	uint16_t output_report_size;
+	uint16_t feature_report_size;
+	WCHAR string[3][MAX_USB_STRING_LENGTH];
+	uint8_t string_index[3];	// man, prod, ser
+};
+
 typedef struct libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
 typedef struct libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
 struct windows_device_priv {
 struct windows_device_priv {
 	uint8_t depth;						// distance to HCD
 	uint8_t depth;						// distance to HCD
 	uint8_t port;						// port number on the hub
 	uint8_t port;						// port number on the hub
+	uint8_t active_config;
 	struct libusb_device *parent_dev;	// access to parent is required for usermode ops
 	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 windows_usb_api_backend const *apib;
+	char *path;							// device interface path
+	int sub_api;						// for WinUSB-like APIs
 	struct {
 	struct {
 		char *path;						// each interface needs a device interface path,
 		char *path;						// each interface needs a device interface path,
 		struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support),
 		struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support),
+		int sub_api;
 		int8_t nb_endpoints;			// and a set of endpoint addresses (USB_MAXENDPOINTS)
 		int8_t nb_endpoints;			// and a set of endpoint addresses (USB_MAXENDPOINTS)
 		uint8_t *endpoint;
 		uint8_t *endpoint;
+		bool restricted_functionality;	// indicates if the interface functionality is restricted
+										// by Windows (eg. HID keyboards or mice cannot do R/W)
 	} usb_interface[USB_MAXINTERFACES];
 	} usb_interface[USB_MAXINTERFACES];
-	uint8_t composite_api_flags;		// composite devices require additional data
-	uint8_t active_config;
+	struct hid_device_priv *hid;
 	USB_DEVICE_DESCRIPTOR dev_descriptor;
 	USB_DEVICE_DESCRIPTOR dev_descriptor;
 	unsigned char **config_descriptor;	// list of pointers to the cached config descriptors
 	unsigned char **config_descriptor;	// list of pointers to the cached config descriptors
 };
 };
@@ -182,15 +238,18 @@ static inline void windows_device_priv_init(libusb_device* dev) {
 	p->parent_dev = NULL;
 	p->parent_dev = NULL;
 	p->path = NULL;
 	p->path = NULL;
 	p->apib = &usb_api_backend[USB_API_UNSUPPORTED];
 	p->apib = &usb_api_backend[USB_API_UNSUPPORTED];
-	p->composite_api_flags = 0;
+	p->sub_api = SUB_API_NOTSET;
+	p->hid = NULL;
 	p->active_config = 0;
 	p->active_config = 0;
 	p->config_descriptor = NULL;
 	p->config_descriptor = NULL;
 	memset(&(p->dev_descriptor), 0, sizeof(USB_DEVICE_DESCRIPTOR));
 	memset(&(p->dev_descriptor), 0, sizeof(USB_DEVICE_DESCRIPTOR));
 	for (i=0; i<USB_MAXINTERFACES; i++) {
 	for (i=0; i<USB_MAXINTERFACES; i++) {
 		p->usb_interface[i].path = NULL;
 		p->usb_interface[i].path = NULL;
 		p->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED];
 		p->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED];
+		p->usb_interface[i].sub_api = SUB_API_NOTSET;
 		p->usb_interface[i].nb_endpoints = 0;
 		p->usb_interface[i].nb_endpoints = 0;
 		p->usb_interface[i].endpoint = NULL;
 		p->usb_interface[i].endpoint = NULL;
+		p->usb_interface[i].restricted_functionality = false;
 	}
 	}
 }
 }
 
 
@@ -203,6 +262,7 @@ static inline void windows_device_priv_release(libusb_device* dev) {
 			safe_free(p->config_descriptor[i]);
 			safe_free(p->config_descriptor[i]);
 	}
 	}
 	safe_free(p->config_descriptor);
 	safe_free(p->config_descriptor);
+	safe_free(p->hid);
 	for (i=0; i<USB_MAXINTERFACES; i++) {
 	for (i=0; i<USB_MAXINTERFACES; i++) {
 		safe_free(p->usb_interface[i].path);
 		safe_free(p->usb_interface[i].path);
 		safe_free(p->usb_interface[i].endpoint);
 		safe_free(p->usb_interface[i].endpoint);
@@ -230,6 +290,9 @@ static inline struct windows_device_handle_priv *_device_handle_priv(
 struct windows_transfer_priv {
 struct windows_transfer_priv {
 	struct winfd pollable_fd;
 	struct winfd pollable_fd;
 	uint8_t interface_number;
 	uint8_t interface_number;
+	uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID
+	uint8_t *hid_dest;   // transfer buffer destination, required for HID
+	size_t hid_expected_size;
 };
 };
 
 
 // used to match a device driver (including filter drivers) against a supported API
 // used to match a device driver (including filter drivers) against a supported API
@@ -239,37 +302,6 @@ struct driver_lookup {
 	const char* designation;	// internal designation (for debug output)
 	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 */
 /* OLE32 dependency */
 DLL_DECLARE_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID));
 DLL_DECLARE_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID));
 
 
@@ -284,6 +316,7 @@ 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, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM));
 DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO,
 DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO,
 			PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD));
 			PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD));
+DLL_DECLARE_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, DWORD));
 DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
 DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
 DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY));
 DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY));
 
 
@@ -589,20 +622,297 @@ typedef struct {
 
 
 typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
 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));
+typedef BOOL (WINAPI *WinUsb_AbortPipe_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR PipeID
+);
+typedef BOOL (WINAPI *WinUsb_ControlTransfer_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	WINUSB_SETUP_PACKET SetupPacket,
+	PUCHAR Buffer,
+	ULONG BufferLength,
+	PULONG LengthTransferred,
+	LPOVERLAPPED Overlapped
+);
+typedef BOOL (WINAPI *WinUsb_FlushPipe_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR PipeID
+);
+typedef BOOL (WINAPI *WinUsb_Free_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle
+);
+typedef BOOL (WINAPI *WinUsb_GetAssociatedInterface_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR AssociatedInterfaceIndex,
+	PWINUSB_INTERFACE_HANDLE AssociatedInterfaceHandle
+);
+typedef BOOL (WINAPI *WinUsb_GetCurrentAlternateSetting_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	PUCHAR AlternateSetting
+);
+typedef BOOL (WINAPI *WinUsb_GetDescriptor_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR DescriptorType,
+	UCHAR Index,
+	USHORT LanguageID,
+	PUCHAR Buffer,
+	ULONG BufferLength,
+	PULONG LengthTransferred
+);
+typedef BOOL (WINAPI *WinUsb_GetOverlappedResult_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	LPOVERLAPPED lpOverlapped,
+	LPDWORD lpNumberOfBytesTransferred,
+	BOOL bWait
+);
+typedef BOOL (WINAPI *WinUsb_GetPipePolicy_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR PipeID,
+	ULONG PolicyType,
+	PULONG ValueLength,
+	PVOID Value
+);
+typedef BOOL (WINAPI *WinUsb_GetPowerPolicy_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	ULONG PolicyType,
+	PULONG ValueLength,
+	PVOID Value
+);
+typedef BOOL (WINAPI *WinUsb_Initialize_t)(
+	HANDLE DeviceHandle,
+	PWINUSB_INTERFACE_HANDLE InterfaceHandle
+);
+typedef BOOL (WINAPI *WinUsb_QueryDeviceInformation_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	ULONG InformationType,
+	PULONG BufferLength,
+	PVOID Buffer
+);
+typedef BOOL (WINAPI *WinUsb_QueryInterfaceSettings_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR AlternateSettingNumber,
+	PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor
+);
+typedef BOOL (WINAPI *WinUsb_QueryPipe_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR AlternateInterfaceNumber,
+	UCHAR PipeIndex,
+	PWINUSB_PIPE_INFORMATION PipeInformation
+);
+typedef BOOL (WINAPI *WinUsb_ReadPipe_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR PipeID,
+	PUCHAR Buffer,
+	ULONG BufferLength,
+	PULONG LengthTransferred,
+	LPOVERLAPPED Overlapped
+);
+typedef BOOL (WINAPI *WinUsb_ResetPipe_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR PipeID
+);
+typedef BOOL (WINAPI *WinUsb_SetCurrentAlternateSetting_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR AlternateSetting
+);
+typedef BOOL (WINAPI *WinUsb_SetPipePolicy_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR PipeID,
+	ULONG PolicyType,
+	ULONG ValueLength,
+	PVOID Value
+);
+typedef BOOL (WINAPI *WinUsb_SetPowerPolicy_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	ULONG PolicyType,
+	ULONG ValueLength,
+	PVOID Value
+);
+typedef BOOL (WINAPI *WinUsb_WritePipe_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle,
+	UCHAR PipeID,
+	PUCHAR Buffer,
+	ULONG BufferLength,
+	PULONG LengthTransferred,
+	LPOVERLAPPED Overlapped
+);
+typedef BOOL (WINAPI *WinUsb_ResetDevice_t)(
+	WINUSB_INTERFACE_HANDLE InterfaceHandle
+);
+
+/* /!\ These must match the ones from the official libusbk.h */
+typedef enum _KUSB_FNID
+{
+	KUSB_FNID_Init,
+	KUSB_FNID_Free,
+	KUSB_FNID_ClaimInterface,
+	KUSB_FNID_ReleaseInterface,
+	KUSB_FNID_SetAltInterface,
+	KUSB_FNID_GetAltInterface,
+	KUSB_FNID_GetDescriptor,
+	KUSB_FNID_ControlTransfer,
+	KUSB_FNID_SetPowerPolicy,
+	KUSB_FNID_GetPowerPolicy,
+	KUSB_FNID_SetConfiguration,
+	KUSB_FNID_GetConfiguration,
+	KUSB_FNID_ResetDevice,
+	KUSB_FNID_Initialize,
+	KUSB_FNID_SelectInterface,
+	KUSB_FNID_GetAssociatedInterface,
+	KUSB_FNID_Clone,
+	KUSB_FNID_QueryInterfaceSettings,
+	KUSB_FNID_QueryDeviceInformation,
+	KUSB_FNID_SetCurrentAlternateSetting,
+	KUSB_FNID_GetCurrentAlternateSetting,
+	KUSB_FNID_QueryPipe,
+	KUSB_FNID_SetPipePolicy,
+	KUSB_FNID_GetPipePolicy,
+	KUSB_FNID_ReadPipe,
+	KUSB_FNID_WritePipe,
+	KUSB_FNID_ResetPipe,
+	KUSB_FNID_AbortPipe,
+	KUSB_FNID_FlushPipe,
+	KUSB_FNID_IsoReadPipe,
+	KUSB_FNID_IsoWritePipe,
+	KUSB_FNID_GetCurrentFrameNumber,
+	KUSB_FNID_GetOverlappedResult,
+	KUSB_FNID_GetProperty,
+	KUSB_FNID_COUNT,
+} KUSB_FNID; 
+
+typedef struct _KLIB_VERSION {
+	INT Major;
+	INT Minor;
+	INT Micro;
+	INT Nano;
+} KLIB_VERSION;
+typedef KLIB_VERSION* PKLIB_VERSION;
+
+typedef BOOL (WINAPI *LibK_GetProcAddress_t)(
+	PVOID* ProcAddress,
+	ULONG DriverID,
+	ULONG FunctionID
+);
+
+typedef VOID (WINAPI *LibK_GetVersion_t)(
+	PKLIB_VERSION Version
+);
+
+struct winusb_interface {
+	bool initialized;
+	WinUsb_AbortPipe_t AbortPipe;
+	WinUsb_ControlTransfer_t ControlTransfer;
+	WinUsb_FlushPipe_t FlushPipe;
+	WinUsb_Free_t Free;
+	WinUsb_GetAssociatedInterface_t GetAssociatedInterface;
+	WinUsb_GetCurrentAlternateSetting_t GetCurrentAlternateSetting;
+	WinUsb_GetDescriptor_t GetDescriptor;
+	WinUsb_GetOverlappedResult_t GetOverlappedResult;
+	WinUsb_GetPipePolicy_t GetPipePolicy;
+	WinUsb_GetPowerPolicy_t GetPowerPolicy;
+	WinUsb_Initialize_t Initialize;
+	WinUsb_QueryDeviceInformation_t QueryDeviceInformation;
+	WinUsb_QueryInterfaceSettings_t QueryInterfaceSettings;
+	WinUsb_QueryPipe_t QueryPipe;
+	WinUsb_ReadPipe_t ReadPipe;
+	WinUsb_ResetPipe_t ResetPipe;
+	WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting;
+	WinUsb_SetPipePolicy_t SetPipePolicy;
+	WinUsb_SetPowerPolicy_t SetPowerPolicy;
+	WinUsb_WritePipe_t WritePipe;
+	WinUsb_ResetDevice_t ResetDevice;
+};
+
+/* hid.dll interface */
+
+#define HIDP_STATUS_SUCCESS  0x110000
+typedef void* PHIDP_PREPARSED_DATA;
+
+#pragma pack(1)
+typedef struct {
+	ULONG Size;
+	USHORT VendorID;
+	USHORT ProductID;
+	USHORT VersionNumber;
+} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
+#pragma pack()
+
+typedef USHORT USAGE;
+typedef struct {
+  USAGE Usage;
+  USAGE UsagePage;
+  USHORT InputReportByteLength;
+  USHORT OutputReportByteLength;
+  USHORT FeatureReportByteLength;
+  USHORT Reserved[17];
+  USHORT NumberLinkCollectionNodes;
+  USHORT NumberInputButtonCaps;
+  USHORT NumberInputValueCaps;
+  USHORT NumberInputDataIndices;
+  USHORT NumberOutputButtonCaps;
+  USHORT NumberOutputValueCaps;
+  USHORT NumberOutputDataIndices;
+  USHORT NumberFeatureButtonCaps;
+  USHORT NumberFeatureValueCaps;
+  USHORT NumberFeatureDataIndices;
+} HIDP_CAPS, *PHIDP_CAPS;
+
+typedef enum _HIDP_REPORT_TYPE {
+  HidP_Input,
+  HidP_Output,
+  HidP_Feature
+} HIDP_REPORT_TYPE;
+
+typedef struct _HIDP_VALUE_CAPS {
+  USAGE  UsagePage;
+  UCHAR  ReportID;
+  BOOLEAN  IsAlias;
+  USHORT  BitField;
+  USHORT  LinkCollection;
+  USAGE  LinkUsage;
+  USAGE  LinkUsagePage;
+  BOOLEAN  IsRange;
+  BOOLEAN  IsStringRange;
+  BOOLEAN  IsDesignatorRange;
+  BOOLEAN  IsAbsolute;
+  BOOLEAN  HasNull;
+  UCHAR  Reserved;
+  USHORT  BitSize;
+  USHORT  ReportCount;
+  USHORT  Reserved2[5];
+  ULONG  UnitsExp;
+  ULONG  Units;
+  LONG  LogicalMin, LogicalMax;
+  LONG  PhysicalMin, PhysicalMax;
+	union {
+	  struct {
+		USAGE  UsageMin, UsageMax;
+		USHORT  StringMin, StringMax;
+		USHORT  DesignatorMin, DesignatorMax;
+		USHORT  DataIndexMin, DataIndexMax;
+	  } Range;
+	  struct {
+		USAGE  Usage, Reserved1;
+		USHORT  StringIndex, Reserved2;
+		USHORT  DesignatorIndex, Reserved3;
+		USHORT  DataIndex, Reserved4;
+	  } NotRange;
+	} u;
+} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS;
+
+DLL_DECLARE(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES));
+DLL_DECLARE(WINAPI, VOID, HidD_GetHidGuid, (LPGUID));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetPreparsedData, (HANDLE, PHIDP_PREPARSED_DATA *));
+DLL_DECLARE(WINAPI, BOOL, HidD_FreePreparsedData, (PHIDP_PREPARSED_DATA));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetManufacturerString, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetProductString, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetSerialNumberString, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, LONG, HidP_GetCaps, (PHIDP_PREPARSED_DATA, PHIDP_CAPS));
+DLL_DECLARE(WINAPI, BOOL, HidD_SetNumInputBuffers, (HANDLE, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_SetFeature, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetFeature, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetInputReport, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_SetOutputReport, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_FlushQueue, (HANDLE));
+DLL_DECLARE(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA));

+ 184 - 0
compat/libusb-1.0/libusb/strerror.c

@@ -0,0 +1,184 @@
+/*
+ * libusb strerror code
+ * Copyright © 2013 Hans de Goede <hdegoede@redhat.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 <locale.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libusb.h"
+#include "libusbi.h"
+
+#if defined(_MSC_VER)
+#define strncasecmp _strnicmp
+#endif
+
+static size_t usbi_locale = 0;
+
+/** \ingroup misc
+ * How to add a new \ref libusb_strerror() translation:
+ * <ol>
+ * <li> Download the latest \c strerror.c from:<br>
+ *      https://raw.github.com/libusbx/libusbx/master/libusb/sterror.c </li>
+ * <li> Open the file in an UTF-8 capable editor </li>
+ * <li> Add the 2 letter <a href="http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes">ISO 639-1</a>
+ *      code for your locale at the end of \c usbi_locale_supported[]<br>
+ *    Eg. for Chinese, you would add "zh" so that:
+ *    \code... usbi_locale_supported[] = { "en", "nl", "fr" };\endcode
+ *    becomes:
+ *    \code... usbi_locale_supported[] = { "en", "nl", "fr", "zh" };\endcode </li>
+ * <li> Copy the <tt>{ / * English (en) * / ... }</tt> section and add it at the end of \c usbi_localized_errors<br>
+ *    Eg. for Chinese, the last section of \c usbi_localized_errors could look like:
+ *    \code
+ *     }, { / * Chinese (zh) * /
+ *         "Success",
+ *         ...
+ *         "Other error",
+ *     }
+ * };\endcode </li>
+ * <li> Translate each of the English messages from the section you copied into your language </li>
+ * <li> Save the file (in UTF-8 format) and send it to \c libusbx-devel\@lists.sourceforge.net </li>
+ * </ol>
+ */
+
+static const char* usbi_locale_supported[] = { "en", "nl", "fr" };
+static const char* usbi_localized_errors[ARRAYSIZE(usbi_locale_supported)][LIBUSB_ERROR_COUNT] = {
+	{ /* English (en) */
+		"Success",
+		"Input/Output Error",
+		"Invalid parameter",
+		"Access denied (insufficient permissions)",
+		"No such device (it may have been disconnected)",
+		"Entity not found",
+		"Resource busy",
+		"Operation timed out",
+		"Overflow",
+		"Pipe error",
+		"System call interrupted (perhaps due to signal)",
+		"Insufficient memory",
+		"Operation not supported or unimplemented on this platform",
+		"Other error",
+	}, { /* Dutch (nl) */
+		"Gelukt",
+		"Invoer-/uitvoerfout",
+		"Ongeldig argument",
+		"Toegang geweigerd (onvoldoende toegangsrechten)",
+		"Apparaat bestaat niet (verbinding met apparaat verbroken?)",
+		"Niet gevonden",
+		"Apparaat of hulpbron is bezig",
+		"Bewerking verlopen",
+		"Waarde is te groot",
+		"Gebroken pijp",
+		"Onderbroken systeemaanroep",
+		"Onvoldoende geheugen beschikbaar",
+		"Bewerking wordt niet ondersteund",
+		"Andere fout",
+	}, { /* French (fr) */
+		"Succès",
+		"Erreur d'entrée/sortie",
+		"Paramètre invalide",
+		"Accès refusé (permissions insuffisantes)",
+		"Périphérique introuvable (peut-être déconnecté)",
+		"Elément introuvable",
+		"Resource déjà occupée",
+		"Operation expirée",
+		"Débordement",
+		"Erreur de pipe",
+		"Appel système abandonné (peut-être à cause d’un signal)",
+		"Mémoire insuffisante",
+		"Opération non supportée or non implémentée sur cette plateforme",
+		"Autre erreur"
+	}
+};
+
+/** \ingroup misc
+ * Set the language, and only the language, not the encoding! used for
+ * translatable libusb messages.
+ *
+ * This takes a locale string in the default setlocale format: lang[-region]
+ * or lang[_country_region][.codeset]. Only the lang part of the string is
+ * used, and only 2 letter ISO 639-1 codes are accepted for it, such as "de".
+ * The optional region, country_region or codeset parts are ignored. This
+ * means that functions which return translatable strings will NOT honor the
+ * specified encoding. 
+ * All strings returned are encoded as UTF-8 strings.
+ *
+ * If libusb_setlocale() is not called, all messages will be in English.
+ *
+ * The following functions return translatable strings: libusb_strerror().
+ * Note that the libusb log messages controlled through libusb_set_debug()
+ * are not translated, they are always in English.
+ *
+ * For POSIX UTF-8 environments if you want libusb to follow the standard
+ * locale settings, call libusb_setlocale(setlocale(LC_MESSAGES, NULL)),
+ * after your app has done its locale setup.
+ *
+ * \param locale locale-string in the form of lang[_country_region][.codeset]
+ * or lang[-region], where lang is a 2 letter ISO 639-1 code
+ * \returns LIBUSB_SUCCESS on success
+ * \returns LIBUSB_ERROR_INVALID_PARAM if the locale doesn't meet the requirements
+ * \returns LIBUSB_ERROR_NOT_FOUND if the requested language is not supported
+ * \returns a LIBUSB_ERROR code on other errors
+ */
+
+int API_EXPORTED libusb_setlocale(const char *locale)
+{
+	size_t i;
+
+	if ( (locale == NULL) || (strlen(locale) < 2)
+	  || ((strlen(locale) > 2) && (locale[2] != '-') && (locale[2] != '_') && (locale[2] != '.')) )
+		return LIBUSB_ERROR_INVALID_PARAM;
+
+	for (i=0; i<ARRAYSIZE(usbi_locale_supported); i++) {
+		if (strncasecmp(usbi_locale_supported[i], locale, 2) == 0)
+			break;
+	}
+	if (i >= ARRAYSIZE(usbi_locale_supported)) {
+		return LIBUSB_ERROR_NOT_FOUND;
+	}
+
+	usbi_locale = i;
+
+	return LIBUSB_SUCCESS;
+}
+
+/** \ingroup misc
+ * Returns a constant string with a short description of the given error code,
+ * this description is intended for displaying to the end user and will be in
+ * the language set by libusb_setlocale().
+ *
+ * The returned string is encoded in UTF-8.
+ *
+ * The messages always start with a capital letter and end without any dot.
+ * The caller must not free() the returned string.
+ *
+ * \param errcode the error code whose description is desired
+ * \returns a short description of the error code in UTF-8 encoding
+ */
+DEFAULT_VISIBILITY const char* LIBUSB_CALL libusb_strerror(enum libusb_error errcode)
+{
+	int errcode_index = -errcode;
+
+	if ((errcode_index < 0) || (errcode_index >= LIBUSB_ERROR_COUNT)) {
+		/* "Other Error", which should always be our last message, is returned */
+		errcode_index = LIBUSB_ERROR_COUNT - 1;
+	}
+
+	return usbi_localized_errors[usbi_locale][errcode_index];
+}

+ 32 - 47
compat/libusb-1.0/libusb/sync.c

@@ -1,6 +1,6 @@
 /*
 /*
- * Synchronous I/O functions for libusb
- * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
+ * Synchronous I/O functions for libusbx
+ * Copyright © 2007-2008 Daniel Drake <dsd@gentoo.org>
  *
  *
  * This library is free software; you can redistribute it and/or
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * modify it under the terms of the GNU Lesser General Public
@@ -17,7 +17,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
  */
 
 
-#include <config.h>
+#include "config.h"
 #include <errno.h>
 #include <errno.h>
 #include <stdint.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdlib.h>
@@ -28,12 +28,12 @@
 /**
 /**
  * @defgroup syncio Synchronous device I/O
  * @defgroup syncio Synchronous device I/O
  *
  *
- * This page documents libusb's synchronous (blocking) API for USB device I/O.
+ * This page documents libusbx's synchronous (blocking) API for USB device I/O.
  * This interface is easy to use but has some limitations. More advanced users
  * 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.
  * may wish to consider using the \ref asyncio "asynchronous I/O API" instead.
  */
  */
 
 
-static void LIBUSB_CALL ctrl_transfer_cb(struct libusb_transfer *transfer)
+static void LIBUSB_CALL sync_transfer_cb(struct libusb_transfer *transfer)
 {
 {
 	int *completed = transfer->user_data;
 	int *completed = transfer->user_data;
 	*completed = 1;
 	*completed = 1;
@@ -41,6 +41,24 @@ static void LIBUSB_CALL ctrl_transfer_cb(struct libusb_transfer *transfer)
 	/* caller interprets result and frees transfer */
 	/* caller interprets result and frees transfer */
 }
 }
 
 
+static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer)
+{
+	int r, *completed = transfer->user_data;
+	struct libusb_context *ctx = HANDLE_CTX(transfer->dev_handle);
+
+	while (!*completed) {
+		r = libusb_handle_events_completed(ctx, completed);
+		if (r < 0) {
+			if (r == LIBUSB_ERROR_INTERRUPTED)
+				continue;
+			usbi_err(ctx, "libusb_handle_events failed: %s, cancelling transfer and retrying",
+				 libusb_error_name(r));
+			libusb_cancel_transfer(transfer);
+			continue;
+		}
+	}
+}
+
 /** \ingroup syncio
 /** \ingroup syncio
  * Perform a USB control transfer.
  * Perform a USB control transfer.
  *
  *
@@ -81,7 +99,7 @@ int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle,
 	if (!transfer)
 	if (!transfer)
 		return LIBUSB_ERROR_NO_MEM;
 		return LIBUSB_ERROR_NO_MEM;
 
 
-	buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE + wLength);
+	buffer = (unsigned char*) malloc(LIBUSB_CONTROL_SETUP_SIZE + wLength);
 	if (!buffer) {
 	if (!buffer) {
 		libusb_free_transfer(transfer);
 		libusb_free_transfer(transfer);
 		return LIBUSB_ERROR_NO_MEM;
 		return LIBUSB_ERROR_NO_MEM;
@@ -93,7 +111,7 @@ int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle,
 		memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength);
 		memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength);
 
 
 	libusb_fill_control_transfer(transfer, dev_handle, buffer,
 	libusb_fill_control_transfer(transfer, dev_handle, buffer,
-		ctrl_transfer_cb, &completed, timeout);
+		sync_transfer_cb, &completed, timeout);
 	transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER;
 	transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER;
 	r = libusb_submit_transfer(transfer);
 	r = libusb_submit_transfer(transfer);
 	if (r < 0) {
 	if (r < 0) {
@@ -101,19 +119,7 @@ int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle,
 		return r;
 		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;
-		}
-	}
+	sync_transfer_wait_for_completion(transfer);
 
 
 	if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
 	if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
 		memcpy(data, libusb_control_transfer_get_data(transfer),
 		memcpy(data, libusb_control_transfer_get_data(transfer),
@@ -149,14 +155,6 @@ int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle,
 	return r;
 	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,
 static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
 	unsigned char endpoint, unsigned char *buffer, int length,
 	unsigned char endpoint, unsigned char *buffer, int length,
 	int *transferred, unsigned int timeout, unsigned char type)
 	int *transferred, unsigned int timeout, unsigned char type)
@@ -169,7 +167,7 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
 		return LIBUSB_ERROR_NO_MEM;
 		return LIBUSB_ERROR_NO_MEM;
 
 
 	libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
 	libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
-		bulk_transfer_cb, &completed, timeout);
+		sync_transfer_cb, &completed, timeout);
 	transfer->type = type;
 	transfer->type = type;
 
 
 	r = libusb_submit_transfer(transfer);
 	r = libusb_submit_transfer(transfer);
@@ -178,19 +176,7 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
 		return r;
 		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;
-		}
-	}
+	sync_transfer_wait_for_completion(transfer);
 
 
 	*transferred = transfer->actual_length;
 	*transferred = transfer->actual_length;
 	switch (transfer->status) {
 	switch (transfer->status) {
@@ -236,9 +222,9 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
  * Not all of the data may have been written.
  * Not all of the data may have been written.
  *
  *
  * Also check <tt>transferred</tt> when dealing with a timeout error code.
  * 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
+ * libusbx may have to split your transfer into a number of chunks to satisfy
  * underlying O/S requirements, meaning that the timeout may expire after
  * 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
+ * the first few chunks have completed. libusbx is careful not to lose any data
  * that may have been transferred; do not assume that timeout conditions
  * that may have been transferred; do not assume that timeout conditions
  * indicate a complete lack of I/O.
  * indicate a complete lack of I/O.
  *
  *
@@ -284,9 +270,9 @@ int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle,
  * writes. Not all of the data may have been written.
  * writes. Not all of the data may have been written.
  *
  *
  * Also check <tt>transferred</tt> when dealing with a timeout error code.
  * 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
+ * libusbx may have to split your transfer into a number of chunks to satisfy
  * underlying O/S requirements, meaning that the timeout may expire after
  * 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
+ * the first few chunks have completed. libusbx is careful not to lose any data
  * that may have been transferred; do not assume that timeout conditions
  * that may have been transferred; do not assume that timeout conditions
  * indicate a complete lack of I/O.
  * indicate a complete lack of I/O.
  *
  *
@@ -319,4 +305,3 @@ int API_EXPORTED libusb_interrupt_transfer(
 	return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
 	return do_sync_bulk_transfer(dev_handle, endpoint, data, length,
 		transferred, timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
 		transferred, timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
 }
 }
-

+ 3 - 3
compat/libusb-1.0/libusb/version.h

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

+ 1 - 0
compat/libusb-1.0/libusb/version_nano.h

@@ -0,0 +1 @@
+#define LIBUSB_NANO 10830

Some files were not shown because too many files changed in this diff