diff options
Diffstat (limited to 'src/3rd_party-static/libusbx-1.0.16')
53 files changed, 0 insertions, 25158 deletions
diff --git a/src/3rd_party-static/libusbx-1.0.16/CMakeLists.txt b/src/3rd_party-static/libusbx-1.0.16/CMakeLists.txt deleted file mode 100644 index 105406c44e..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -set(LIBUSB_INCLUDE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -set(LIBUSB_INCLUDE_DIRECTORY ${LIBUSB_INCLUDE_DIRECTORY} PARENT_SCOPE) - -set(LIBUSB_LIBS_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) -set(LIBUSB_LIBS_DIRECTORY ${LIBUSB_LIBS_DIRECTORY} PARENT_SCOPE) - -include_directories ( - ./libusb/os/ - ./libusb/ - ./ -) - -set (LIBUSB_SOURCES - ./libusb/core.c - ./libusb/descriptor.c - ./libusb/hotplug.c - ./libusb/io.c - ./libusb/strerror.c - ./libusb/sync.c - ./libusb/os/linux_udev.c - ./libusb/os/linux_netlink.c - ./libusb/os/linux_usbfs.c - ./libusb/os/poll_posix.c - ./libusb/os/threads_posix.c -) - -add_library("Libusb-1.0.16" ${LIBUSB_SOURCES}) - - -target_link_libraries("Libusb-1.0.16" udev) diff --git a/src/3rd_party-static/libusbx-1.0.16/config.h b/src/3rd_party-static/libusbx-1.0.16/config.h deleted file mode 100644 index 3c4543f2f1..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/config.h +++ /dev/null @@ -1,135 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Default visibility */ -#define DEFAULT_VISIBILITY __attribute__((visibility("default"))) - -/* Start with debug message logging enabled */ -/* #undef ENABLE_DEBUG_LOGGING */ - -/* Message logging */ -#define ENABLE_LOGGING 1 - -/* Define to 1 if you have the <dlfcn.h> header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the `gettimeofday' function. */ -#define HAVE_GETTIMEOFDAY 1 - -/* Define to 1 if you have the <inttypes.h> header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `udev' library (-ludev). */ -#define HAVE_LIBUDEV 1 - -/* Define to 1 if you have the <libudev.h> header file. */ -#define HAVE_LIBUDEV_H 1 - -/* Define to 1 if you have the <linux/filter.h> header file. */ -/* #undef HAVE_LINUX_FILTER_H */ - -/* Define to 1 if you have the <linux/netlink.h> header file. */ -/* #undef HAVE_LINUX_NETLINK_H */ - -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the <poll.h> header file. */ -#define HAVE_POLL_H 1 - -/* Define to 1 if you have the <signal.h> header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define to 1 if you have the <stdint.h> header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the <strings.h> header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if the system has the type `struct timespec'. */ -#define HAVE_STRUCT_TIMESPEC 1 - -/* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the <sys/time.h> header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the <unistd.h> header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#define LT_OBJDIR ".libs/" - -/* Define to 1 if your C compiler doesn't accept -c and -o together. */ -/* #undef NO_MINUS_C_MINUS_O */ - -/* Darwin backend */ -/* #undef OS_DARWIN */ - -/* Linux backend */ -#define OS_LINUX 1 - -/* OpenBSD/NetBSD backend */ -/* #undef OS_OPENBSD */ - -/* Windows backend */ -/* #undef OS_WINDOWS */ - -/* Name of package */ -#define PACKAGE "libusbx" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "libusbx-devel@lists.sourceforge.net" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libusbx" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libusbx 1.0.16" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libusbx" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "http://libusbx.org" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "1.0.16" - -/* type of second poll() argument */ -#define POLL_NFDS_TYPE nfds_t - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Use POSIX Threads */ -#define THREADS_POSIX 1 - -/* timerfd headers available */ -#define USBI_TIMERFD_AVAILABLE 1 - -/* Use udev for device enumeration/hotplug */ -#define USE_UDEV 1 - -/* Version number of package */ -#define VERSION "1.0.16" - -/* Use GNU extensions */ -#define _GNU_SOURCE 1 - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-core.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-core.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-core.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-darwin_usb.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-darwin_usb.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-darwin_usb.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-descriptor.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-descriptor.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-descriptor.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-hotplug.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-hotplug.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-hotplug.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-io.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-io.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-io.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-linux_netlink.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-linux_netlink.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-linux_netlink.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-linux_udev.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-linux_udev.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-linux_udev.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-linux_usbfs.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-linux_usbfs.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-linux_usbfs.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-openbsd_usb.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-openbsd_usb.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-openbsd_usb.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-poll_posix.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-poll_posix.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-poll_posix.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-poll_windows.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-poll_windows.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-poll_windows.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-strerror.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-strerror.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-strerror.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-sync.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-sync.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-sync.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-threads_posix.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-threads_posix.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-threads_posix.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-threads_windows.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-threads_windows.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-threads_windows.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-windows_usb.Plo b/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-windows_usb.Plo deleted file mode 100644 index 9ce06a81ea..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/.deps/libusb_1_0_la-windows_usb.Plo +++ /dev/null @@ -1 +0,0 @@ -# dummy diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/Makefile.am b/src/3rd_party-static/libusbx-1.0.16/libusb/Makefile.am deleted file mode 100644 index 7f9c1f9093..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/Makefile.am +++ /dev/null @@ -1,68 +0,0 @@ -all: libusb-1.0.la libusb-1.0.dll - -lib_LTLIBRARIES = libusb-1.0.la - -POSIX_POLL_SRC = os/poll_posix.c -LINUX_USBFS_SRC = os/linux_usbfs.c -DARWIN_USB_SRC = os/darwin_usb.c -OPENBSD_USB_SRC = os/openbsd_usb.c -WINDOWS_USB_SRC = os/poll_windows.c os/windows_usb.c libusb-1.0.rc libusb-1.0.def -WINCE_USB_SRC = os/wince_usb.c os/wince_usb.h - -EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(OPENBSD_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 - -if OS_LINUX - -if USE_UDEV -OS_SRC = $(LINUX_USBFS_SRC) $(POSIX_POLL_SRC) \ - os/linux_udev.c -else -OS_SRC = $(LINUX_USBFS_SRC) $(POSIX_POLL_SRC) \ - os/linux_netlink.c -endif - -endif - -if OS_DARWIN -OS_SRC = $(DARWIN_USB_SRC) $(POSIX_POLL_SRC) -AM_CFLAGS_EXT = -no-cpp-precomp -endif - -if OS_OPENBSD -OS_SRC = $(OPENBSD_USB_SRC) $(POSIX_POLL_SRC) -endif - -if OS_WINDOWS -OS_SRC = $(WINDOWS_USB_SRC) - -.rc.lo: - $(AM_V_GEN)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@ - -libusb-1.0.rc: version.h 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 - -if THREADS_POSIX -THREADS_SRC = os/threads_posix.h os/threads_posix.c -else -THREADS_SRC = os/threads_windows.h os/threads_windows.c -endif - -libusb_1_0_la_CFLAGS = $(AM_CFLAGS) -libusb_1_0_la_LDFLAGS = $(LTLDFLAGS) -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 -hdr_HEADERS = libusb.h diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/Makefile.in b/src/3rd_party-static/libusbx-1.0.16/libusb/Makefile.in deleted file mode 100644 index 2461c45a80..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/Makefile.in +++ /dev/null @@ -1,860 +0,0 @@ -# Makefile.in generated by automake 1.13.4 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2013 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - - -VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = libusb -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/depcomp $(hdr_HEADERS) -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ - $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ - $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/libusb/version.h $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(hdrdir)" -LTLIBRARIES = $(lib_LTLIBRARIES) -libusb_1_0_la_LIBADD = -am__libusb_1_0_la_SOURCES_DIST = libusbi.h core.c descriptor.c io.c \ - strerror.c sync.c os/linux_usbfs.h os/darwin_usb.h \ - os/windows_usb.h os/windows_common.h hotplug.h hotplug.c \ - os/threads_windows.h os/threads_windows.c os/threads_posix.h \ - os/threads_posix.c os/darwin_usb.c os/poll_posix.c \ - os/linux_usbfs.c os/linux_netlink.c os/linux_udev.c \ - os/openbsd_usb.c os/poll_windows.c os/windows_usb.c \ - libusb-1.0.rc libusb-1.0.def os/poll_posix.h os/poll_windows.h -@THREADS_POSIX_FALSE@am__objects_1 = libusb_1_0_la-threads_windows.lo -@THREADS_POSIX_TRUE@am__objects_1 = libusb_1_0_la-threads_posix.lo -am__objects_2 = libusb_1_0_la-darwin_usb.lo -am__objects_3 = libusb_1_0_la-poll_posix.lo -am__objects_4 = libusb_1_0_la-linux_usbfs.lo -am__objects_5 = libusb_1_0_la-openbsd_usb.lo -am__objects_6 = libusb_1_0_la-poll_windows.lo \ - libusb_1_0_la-windows_usb.lo libusb-1.0.lo -@OS_DARWIN_FALSE@@OS_LINUX_FALSE@@OS_OPENBSD_FALSE@@OS_WINDOWS_TRUE@am__objects_7 = $(am__objects_6) -@OS_DARWIN_FALSE@@OS_LINUX_FALSE@@OS_OPENBSD_TRUE@am__objects_7 = $(am__objects_5) \ -@OS_DARWIN_FALSE@@OS_LINUX_FALSE@@OS_OPENBSD_TRUE@ $(am__objects_3) -@OS_DARWIN_FALSE@@OS_LINUX_TRUE@@USE_UDEV_FALSE@am__objects_7 = $(am__objects_4) \ -@OS_DARWIN_FALSE@@OS_LINUX_TRUE@@USE_UDEV_FALSE@ $(am__objects_3) \ -@OS_DARWIN_FALSE@@OS_LINUX_TRUE@@USE_UDEV_FALSE@ libusb_1_0_la-linux_netlink.lo -@OS_DARWIN_FALSE@@OS_LINUX_TRUE@@USE_UDEV_TRUE@am__objects_7 = $(am__objects_4) \ -@OS_DARWIN_FALSE@@OS_LINUX_TRUE@@USE_UDEV_TRUE@ $(am__objects_3) \ -@OS_DARWIN_FALSE@@OS_LINUX_TRUE@@USE_UDEV_TRUE@ libusb_1_0_la-linux_udev.lo -@OS_DARWIN_TRUE@am__objects_7 = $(am__objects_2) $(am__objects_3) -am_libusb_1_0_la_OBJECTS = libusb_1_0_la-core.lo \ - libusb_1_0_la-descriptor.lo libusb_1_0_la-io.lo \ - libusb_1_0_la-strerror.lo libusb_1_0_la-sync.lo \ - libusb_1_0_la-hotplug.lo $(am__objects_1) $(am__objects_7) -libusb_1_0_la_OBJECTS = $(am_libusb_1_0_la_OBJECTS) -AM_V_lt = $(am__v_lt_@AM_V@) -am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) -am__v_lt_0 = --silent -am__v_lt_1 = -libusb_1_0_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libusb_1_0_la_CFLAGS) \ - $(CFLAGS) $(libusb_1_0_la_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -SOURCES = $(libusb_1_0_la_SOURCES) -DIST_SOURCES = $(am__libusb_1_0_la_SOURCES_DIST) -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -HEADERS = $(hdr_HEADERS) -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_CFLAGS = @AM_CFLAGS@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLDFLAGS = @LTLDFLAGS@ -LTLIBOBJS = @LTLIBOBJS@ -MAINT = @MAINT@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OS_DARWIN = @OS_DARWIN@ -OS_LINUX = @OS_LINUX@ -OS_OPENBSD = @OS_OPENBSD@ -OS_WINDOWS = @OS_WINDOWS@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -RANLIB = @RANLIB@ -RC = @RC@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -USE_UDEV = @USE_UDEV@ -VERSION = @VERSION@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -lib_LTLIBRARIES = libusb-1.0.la -POSIX_POLL_SRC = os/poll_posix.c -LINUX_USBFS_SRC = os/linux_usbfs.c -DARWIN_USB_SRC = os/darwin_usb.c -OPENBSD_USB_SRC = os/openbsd_usb.c -WINDOWS_USB_SRC = os/poll_windows.c os/windows_usb.c libusb-1.0.rc libusb-1.0.def -WINCE_USB_SRC = os/wince_usb.c os/wince_usb.h -EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(OPENBSD_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_DARWIN_TRUE@OS_SRC = $(DARWIN_USB_SRC) $(POSIX_POLL_SRC) -@OS_LINUX_TRUE@@USE_UDEV_FALSE@OS_SRC = $(LINUX_USBFS_SRC) $(POSIX_POLL_SRC) \ -@OS_LINUX_TRUE@@USE_UDEV_FALSE@ os/linux_netlink.c - -@OS_LINUX_TRUE@@USE_UDEV_TRUE@OS_SRC = $(LINUX_USBFS_SRC) $(POSIX_POLL_SRC) \ -@OS_LINUX_TRUE@@USE_UDEV_TRUE@ os/linux_udev.c - -@OS_OPENBSD_TRUE@OS_SRC = $(OPENBSD_USB_SRC) $(POSIX_POLL_SRC) -@OS_WINDOWS_TRUE@OS_SRC = $(WINDOWS_USB_SRC) -@OS_DARWIN_TRUE@AM_CFLAGS_EXT = -no-cpp-precomp -@THREADS_POSIX_FALSE@THREADS_SRC = os/threads_windows.h os/threads_windows.c -@THREADS_POSIX_TRUE@THREADS_SRC = os/threads_posix.h os/threads_posix.c -libusb_1_0_la_CFLAGS = $(AM_CFLAGS) -libusb_1_0_la_LDFLAGS = $(LTLDFLAGS) -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 -hdr_HEADERS = libusb.h -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj .rc -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libusb/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu libusb/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -install-libLTLIBRARIES: $(lib_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ - } - -uninstall-libLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ - done - -clean-libLTLIBRARIES: - -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) - @list='$(lib_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -libusb-1.0.la: $(libusb_1_0_la_OBJECTS) $(libusb_1_0_la_DEPENDENCIES) $(EXTRA_libusb_1_0_la_DEPENDENCIES) - $(AM_V_CCLD)$(libusb_1_0_la_LINK) -rpath $(libdir) $(libusb_1_0_la_OBJECTS) $(libusb_1_0_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-core.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-darwin_usb.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-descriptor.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-hotplug.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-io.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-linux_netlink.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-linux_udev.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-linux_usbfs.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-openbsd_usb.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-poll_posix.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-poll_windows.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-strerror.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-sync.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-threads_posix.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-threads_windows.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb_1_0_la-windows_usb.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< - -libusb_1_0_la-core.lo: core.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-core.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-core.Tpo -c -o libusb_1_0_la-core.lo `test -f 'core.c' || echo '$(srcdir)/'`core.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-core.Tpo $(DEPDIR)/libusb_1_0_la-core.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='core.c' object='libusb_1_0_la-core.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-core.lo `test -f 'core.c' || echo '$(srcdir)/'`core.c - -libusb_1_0_la-descriptor.lo: descriptor.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-descriptor.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-descriptor.Tpo -c -o libusb_1_0_la-descriptor.lo `test -f 'descriptor.c' || echo '$(srcdir)/'`descriptor.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-descriptor.Tpo $(DEPDIR)/libusb_1_0_la-descriptor.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='descriptor.c' object='libusb_1_0_la-descriptor.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-descriptor.lo `test -f 'descriptor.c' || echo '$(srcdir)/'`descriptor.c - -libusb_1_0_la-io.lo: io.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-io.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-io.Tpo -c -o libusb_1_0_la-io.lo `test -f 'io.c' || echo '$(srcdir)/'`io.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-io.Tpo $(DEPDIR)/libusb_1_0_la-io.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='io.c' object='libusb_1_0_la-io.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-io.lo `test -f 'io.c' || echo '$(srcdir)/'`io.c - -libusb_1_0_la-strerror.lo: strerror.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-strerror.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-strerror.Tpo -c -o libusb_1_0_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-strerror.Tpo $(DEPDIR)/libusb_1_0_la-strerror.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strerror.c' object='libusb_1_0_la-strerror.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c - -libusb_1_0_la-sync.lo: sync.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-sync.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-sync.Tpo -c -o libusb_1_0_la-sync.lo `test -f 'sync.c' || echo '$(srcdir)/'`sync.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-sync.Tpo $(DEPDIR)/libusb_1_0_la-sync.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sync.c' object='libusb_1_0_la-sync.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-sync.lo `test -f 'sync.c' || echo '$(srcdir)/'`sync.c - -libusb_1_0_la-hotplug.lo: hotplug.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-hotplug.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-hotplug.Tpo -c -o libusb_1_0_la-hotplug.lo `test -f 'hotplug.c' || echo '$(srcdir)/'`hotplug.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-hotplug.Tpo $(DEPDIR)/libusb_1_0_la-hotplug.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hotplug.c' object='libusb_1_0_la-hotplug.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-hotplug.lo `test -f 'hotplug.c' || echo '$(srcdir)/'`hotplug.c - -libusb_1_0_la-threads_windows.lo: os/threads_windows.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-threads_windows.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-threads_windows.Tpo -c -o libusb_1_0_la-threads_windows.lo `test -f 'os/threads_windows.c' || echo '$(srcdir)/'`os/threads_windows.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-threads_windows.Tpo $(DEPDIR)/libusb_1_0_la-threads_windows.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/threads_windows.c' object='libusb_1_0_la-threads_windows.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-threads_windows.lo `test -f 'os/threads_windows.c' || echo '$(srcdir)/'`os/threads_windows.c - -libusb_1_0_la-threads_posix.lo: os/threads_posix.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-threads_posix.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-threads_posix.Tpo -c -o libusb_1_0_la-threads_posix.lo `test -f 'os/threads_posix.c' || echo '$(srcdir)/'`os/threads_posix.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-threads_posix.Tpo $(DEPDIR)/libusb_1_0_la-threads_posix.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/threads_posix.c' object='libusb_1_0_la-threads_posix.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-threads_posix.lo `test -f 'os/threads_posix.c' || echo '$(srcdir)/'`os/threads_posix.c - -libusb_1_0_la-darwin_usb.lo: os/darwin_usb.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-darwin_usb.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-darwin_usb.Tpo -c -o libusb_1_0_la-darwin_usb.lo `test -f 'os/darwin_usb.c' || echo '$(srcdir)/'`os/darwin_usb.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-darwin_usb.Tpo $(DEPDIR)/libusb_1_0_la-darwin_usb.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/darwin_usb.c' object='libusb_1_0_la-darwin_usb.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-darwin_usb.lo `test -f 'os/darwin_usb.c' || echo '$(srcdir)/'`os/darwin_usb.c - -libusb_1_0_la-poll_posix.lo: os/poll_posix.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-poll_posix.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-poll_posix.Tpo -c -o libusb_1_0_la-poll_posix.lo `test -f 'os/poll_posix.c' || echo '$(srcdir)/'`os/poll_posix.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-poll_posix.Tpo $(DEPDIR)/libusb_1_0_la-poll_posix.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/poll_posix.c' object='libusb_1_0_la-poll_posix.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-poll_posix.lo `test -f 'os/poll_posix.c' || echo '$(srcdir)/'`os/poll_posix.c - -libusb_1_0_la-linux_usbfs.lo: os/linux_usbfs.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-linux_usbfs.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-linux_usbfs.Tpo -c -o libusb_1_0_la-linux_usbfs.lo `test -f 'os/linux_usbfs.c' || echo '$(srcdir)/'`os/linux_usbfs.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-linux_usbfs.Tpo $(DEPDIR)/libusb_1_0_la-linux_usbfs.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/linux_usbfs.c' object='libusb_1_0_la-linux_usbfs.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-linux_usbfs.lo `test -f 'os/linux_usbfs.c' || echo '$(srcdir)/'`os/linux_usbfs.c - -libusb_1_0_la-linux_netlink.lo: os/linux_netlink.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-linux_netlink.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-linux_netlink.Tpo -c -o libusb_1_0_la-linux_netlink.lo `test -f 'os/linux_netlink.c' || echo '$(srcdir)/'`os/linux_netlink.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-linux_netlink.Tpo $(DEPDIR)/libusb_1_0_la-linux_netlink.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/linux_netlink.c' object='libusb_1_0_la-linux_netlink.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-linux_netlink.lo `test -f 'os/linux_netlink.c' || echo '$(srcdir)/'`os/linux_netlink.c - -libusb_1_0_la-linux_udev.lo: os/linux_udev.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-linux_udev.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-linux_udev.Tpo -c -o libusb_1_0_la-linux_udev.lo `test -f 'os/linux_udev.c' || echo '$(srcdir)/'`os/linux_udev.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-linux_udev.Tpo $(DEPDIR)/libusb_1_0_la-linux_udev.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/linux_udev.c' object='libusb_1_0_la-linux_udev.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-linux_udev.lo `test -f 'os/linux_udev.c' || echo '$(srcdir)/'`os/linux_udev.c - -libusb_1_0_la-openbsd_usb.lo: os/openbsd_usb.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-openbsd_usb.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-openbsd_usb.Tpo -c -o libusb_1_0_la-openbsd_usb.lo `test -f 'os/openbsd_usb.c' || echo '$(srcdir)/'`os/openbsd_usb.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-openbsd_usb.Tpo $(DEPDIR)/libusb_1_0_la-openbsd_usb.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/openbsd_usb.c' object='libusb_1_0_la-openbsd_usb.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-openbsd_usb.lo `test -f 'os/openbsd_usb.c' || echo '$(srcdir)/'`os/openbsd_usb.c - -libusb_1_0_la-poll_windows.lo: os/poll_windows.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-poll_windows.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-poll_windows.Tpo -c -o libusb_1_0_la-poll_windows.lo `test -f 'os/poll_windows.c' || echo '$(srcdir)/'`os/poll_windows.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-poll_windows.Tpo $(DEPDIR)/libusb_1_0_la-poll_windows.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/poll_windows.c' object='libusb_1_0_la-poll_windows.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-poll_windows.lo `test -f 'os/poll_windows.c' || echo '$(srcdir)/'`os/poll_windows.c - -libusb_1_0_la-windows_usb.lo: os/windows_usb.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -MT libusb_1_0_la-windows_usb.lo -MD -MP -MF $(DEPDIR)/libusb_1_0_la-windows_usb.Tpo -c -o libusb_1_0_la-windows_usb.lo `test -f 'os/windows_usb.c' || echo '$(srcdir)/'`os/windows_usb.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libusb_1_0_la-windows_usb.Tpo $(DEPDIR)/libusb_1_0_la-windows_usb.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='os/windows_usb.c' object='libusb_1_0_la-windows_usb.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libusb_1_0_la_CFLAGS) $(CFLAGS) -c -o libusb_1_0_la-windows_usb.lo `test -f 'os/windows_usb.c' || echo '$(srcdir)/'`os/windows_usb.c - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -install-hdrHEADERS: $(hdr_HEADERS) - @$(NORMAL_INSTALL) - @list='$(hdr_HEADERS)'; test -n "$(hdrdir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(hdrdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(hdrdir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(hdrdir)'"; \ - $(INSTALL_HEADER) $$files "$(DESTDIR)$(hdrdir)" || exit $$?; \ - done - -uninstall-hdrHEADERS: - @$(NORMAL_UNINSTALL) - @list='$(hdr_HEADERS)'; test -n "$(hdrdir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(hdrdir)'; $(am__uninstall_files_from_dir) - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LTLIBRARIES) $(HEADERS) -installdirs: - for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(hdrdir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ - mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-hdrHEADERS - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-libLTLIBRARIES - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-hdrHEADERS uninstall-libLTLIBRARIES - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ - clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ - ctags-am distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-hdrHEADERS install-html \ - install-html-am install-info install-info-am \ - install-libLTLIBRARIES install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags tags-am uninstall uninstall-am uninstall-hdrHEADERS \ - uninstall-libLTLIBRARIES - -all: libusb-1.0.la libusb-1.0.dll - -@OS_WINDOWS_TRUE@.rc.lo: -@OS_WINDOWS_TRUE@ $(AM_V_GEN)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@ - -@OS_WINDOWS_TRUE@libusb-1.0.rc: version.h version_nano.h - -libusb-1.0.dll: libusb-1.0.def -# Rebuild the import lib from the .def so that MS and MinGW DLLs can be interchanged -@CREATE_IMPORT_LIB_TRUE@ $(AM_V_GEN)$(DLLTOOL) $(DLLTOOLFLAGS) --kill-at --input-def $(srcdir)/libusb-1.0.def --dllname $@ --output-lib .libs/$@.a - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/core.c b/src/3rd_party-static/libusbx-1.0.16/libusb/core.c deleted file mode 100644 index e29e8df254..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/core.c +++ /dev/null @@ -1,2228 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */ -/* - * Core functions for libusbx - * Copyright © 2012-2013 Nathan Hjelm <hjelmn@cs.unm.edu> - * Copyright © 2007-2008 Daniel Drake <dsd@gentoo.org> - * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include <errno.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif - -#ifdef __ANDROID__ -#include <android/log.h> -#endif - -#include "libusbi.h" -#include "hotplug.h" - -#if defined(OS_LINUX) -const struct usbi_os_backend * const usbi_backend = &linux_usbfs_backend; -#elif defined(OS_DARWIN) -const struct usbi_os_backend * const usbi_backend = &darwin_backend; -#elif defined(OS_OPENBSD) -const struct usbi_os_backend * const usbi_backend = &openbsd_backend; -#elif defined(OS_WINDOWS) -const struct usbi_os_backend * const usbi_backend = &windows_backend; -#elif defined(OS_WINCE) -const struct usbi_os_backend * const usbi_backend = &wince_backend; -#else -#error "Unsupported OS" -#endif - -struct libusb_context *usbi_default_context = NULL; -const struct libusb_version libusb_version_internal = - { LIBUSB_MAJOR, LIBUSB_MINOR, LIBUSB_MICRO, LIBUSB_NANO, - LIBUSB_RC, "http://libusbx.org" }; -static int default_context_refcnt = 0; -static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER; -static struct timeval timestamp_origin = { 0, 0 }; - -usbi_mutex_static_t active_contexts_lock = USBI_MUTEX_INITIALIZER; -struct list_head active_contexts_list; - -/** - * \mainpage libusbx-1.0 API Reference - * - * \section intro Introduction - * - * libusbx is an open source library that allows you to communicate with USB - * devices from userspace. For more info, see the - * <a href="http://libusbx.org">libusbx homepage</a>. - * - * This documentation is aimed at application developers wishing to - * communicate with USB peripherals from their own software. After reviewing - * this documentation, feedback and questions can be sent to the - * <a href="http://mailing-list.libusbx.org">libusbx-devel mailing list</a>. - * - * This documentation assumes knowledge of how to operate USB devices from - * a software standpoint (descriptors, configurations, interfaces, endpoints, - * control/bulk/interrupt/isochronous transfers, etc). Full information - * can be found in the <a href="http://www.usb.org/developers/docs/">USB 3.0 - * Specification</a> which is available for free download. You can probably - * find less verbose introductions by searching the web. - * - * \section features Library features - * - * - All transfer types supported (control/bulk/interrupt/isochronous) - * - 2 transfer interfaces: - * -# Synchronous (simple) - * -# Asynchronous (more complicated, but more powerful) - * - Thread safe (although the asynchronous interface means that you - * usually won't need to thread) - * - Lightweight with lean API - * - Compatible with libusb-0.1 through the libusb-compat-0.1 translation layer - * - Hotplug support (on some platforms). See \ref hotplug. - * - * \section gettingstarted Getting Started - * - * To begin reading the API documentation, start with the Modules page which - * links to the different categories of libusbx's functionality. - * - * One decision you will have to make is whether to use the synchronous - * or the asynchronous data transfer interface. The \ref io documentation - * provides some insight into this topic. - * - * Some example programs can be found in the libusbx source distribution under - * the "examples" subdirectory. The libusbx homepage includes a list of - * real-life project examples which use libusbx. - * - * \section errorhandling Error handling - * - * libusbx functions typically return 0 on success or a negative error code - * on failure. These negative error codes relate to LIBUSB_ERROR constants - * which are listed on the \ref misc "miscellaneous" documentation page. - * - * \section msglog Debug message logging - * - * libusbx uses stderr for all logging. By default, logging is set to NONE, - * which means that no output will be produced. However, unless the library - * has been compiled with logging disabled, then any application calls to - * libusb_set_debug(), or the setting of the environmental variable - * LIBUSB_DEBUG outside of the application, can result in logging being - * produced. Your application should therefore not close stderr, but instead - * direct it to the null device if its output is undesireable. - * - * The libusb_set_debug() function can be used to enable logging of certain - * messages. Under standard configuration, libusbx doesn't really log much - * so you are advised to use this function to enable all error/warning/ - * informational messages. It will help debug problems with your software. - * - * The logged messages are unstructured. There is no one-to-one correspondence - * between messages being logged and success or failure return codes from - * libusbx functions. There is no format to the messages, so you should not - * try to capture or parse them. They are not and will not be localized. - * These messages are not intended to being passed to your application user; - * instead, you should interpret the error codes returned from libusbx functions - * and provide appropriate notification to the user. The messages are simply - * there to aid you as a programmer, and if you're confused because you're - * getting a strange error code from a libusbx function, enabling message - * logging may give you a suitable explanation. - * - * The LIBUSB_DEBUG environment variable can be used to enable message logging - * at run-time. This environment variable should be set to a log level number, - * which is interpreted the same as the libusb_set_debug() parameter. When this - * environment variable is set, the message logging verbosity level is fixed - * and libusb_set_debug() effectively does nothing. - * - * libusbx can be compiled without any logging functions, useful for embedded - * systems. In this case, libusb_set_debug() and the LIBUSB_DEBUG environment - * variable have no effects. - * - * libusbx can also be compiled with verbose debugging messages always. When - * the library is compiled in this way, all messages of all verbosities are - * always logged. libusb_set_debug() and the LIBUSB_DEBUG environment variable - * have no effects. - * - * \section remarks Other remarks - * - * libusbx does have imperfections. The \ref caveats "caveats" page attempts - * to document these. - */ - -/** - * \page caveats Caveats - * - * \section devresets Device resets - * - * The libusb_reset_device() function allows you to reset a device. If your - * program has to call such a function, it should obviously be aware that - * the reset will cause device state to change (e.g. register values may be - * reset). - * - * The problem is that any other program could reset the device your program - * is working with, at any time. libusbx does not offer a mechanism to inform - * you when this has happened, so if someone else resets your device it will - * not be clear to your own program why the device state has changed. - * - * Ultimately, this is a limitation of writing drivers in userspace. - * Separation from the USB stack in the underlying kernel makes it difficult - * for the operating system to deliver such notifications to your program. - * The Linux kernel USB stack allows such reset notifications to be delivered - * to in-kernel USB drivers, but it is not clear how such notifications could - * be delivered to second-class drivers that live in userspace. - * - * \section blockonly Blocking-only functionality - * - * The functionality listed below is only available through synchronous, - * blocking functions. There are no asynchronous/non-blocking alternatives, - * and no clear ways of implementing these. - * - * - Configuration activation (libusb_set_configuration()) - * - Interface/alternate setting activation (libusb_set_interface_alt_setting()) - * - Releasing of interfaces (libusb_release_interface()) - * - Clearing of halt/stall condition (libusb_clear_halt()) - * - Device resets (libusb_reset_device()) - * - * \section configsel Configuration selection and handling - * - * When libusbx presents a device handle to an application, there is a chance - * that the corresponding device may be in unconfigured state. For devices - * with multiple configurations, there is also a chance that the configuration - * currently selected is not the one that the application wants to use. - * - * The obvious solution is to add a call to libusb_set_configuration() early - * on during your device initialization routines, but there are caveats to - * be aware of: - * -# If the device is already in the desired configuration, calling - * libusb_set_configuration() using the same configuration value will cause - * a lightweight device reset. This may not be desirable behaviour. - * -# libusbx will be unable to change configuration if the device is in - * another configuration and other programs or drivers have claimed - * interfaces under that configuration. - * -# In the case where the desired configuration is already active, libusbx - * may not even be able to perform a lightweight device reset. For example, - * take my USB keyboard with fingerprint reader: I'm interested in driving - * the fingerprint reader interface through libusbx, but the kernel's - * USB-HID driver will almost always have claimed the keyboard interface. - * Because the kernel has claimed an interface, it is not even possible to - * perform the lightweight device reset, so libusb_set_configuration() will - * fail. (Luckily the device in question only has a single configuration.) - * - * One solution to some of the above problems is to consider the currently - * active configuration. If the configuration we want is already active, then - * we don't have to select any configuration: -\code -cfg = libusb_get_configuration(dev); -if (cfg != desired) - libusb_set_configuration(dev, desired); -\endcode - * - * This is probably suitable for most scenarios, but is inherently racy: - * another application or driver may change the selected configuration - * <em>after</em> the libusb_get_configuration() call. - * - * Even in cases where libusb_set_configuration() succeeds, consider that other - * applications or drivers may change configuration after your application - * calls libusb_set_configuration(). - * - * One possible way to lock your device into a specific configuration is as - * follows: - * -# Set the desired configuration (or use the logic above to realise that - * it is already in the desired configuration) - * -# Claim the interface that you wish to use - * -# Check that the currently active configuration is the one that you want - * to use. - * - * The above method works because once an interface is claimed, no application - * or driver is able to select another configuration. - * - * \section earlycomp Early transfer completion - * - * NOTE: This section is currently Linux-centric. I am not sure if any of these - * considerations apply to Darwin or other platforms. - * - * When a transfer completes early (i.e. when less data is received/sent in - * any one packet than the transfer buffer allows for) then libusbx is designed - * to terminate the transfer immediately, not transferring or receiving any - * more data unless other transfers have been queued by the user. - * - * On legacy platforms, libusbx is unable to do this in all situations. After - * the incomplete packet occurs, "surplus" data may be transferred. For recent - * versions of libusbx, this information is kept (the data length of the - * transfer is updated) and, for device-to-host transfers, any surplus data was - * added to the buffer. Still, this is not a nice solution because it loses the - * information about the end of the short packet, and the user probably wanted - * that surplus data to arrive in the next logical transfer. - * - * - * \section zlp Zero length packets - * - * - libusbx is able to send a packet of zero length to an endpoint simply by - * submitting a transfer of zero length. - * - The \ref libusb_transfer_flags::LIBUSB_TRANSFER_ADD_ZERO_PACKET - * "LIBUSB_TRANSFER_ADD_ZERO_PACKET" flag is currently only supported on Linux. - */ - -/** - * \page contexts Contexts - * - * It is possible that libusbx may be used simultaneously from two independent - * libraries linked into the same executable. For example, if your application - * has a plugin-like system which allows the user to dynamically load a range - * of modules into your program, it is feasible that two independently - * developed modules may both use libusbx. - * - * libusbx is written to allow for these multiple user scenarios. The two - * "instances" of libusbx will not interfere: libusb_set_debug() calls - * from one user will not affect the same settings for other users, other - * users can continue using libusbx after one of them calls libusb_exit(), etc. - * - * This is made possible through libusbx's <em>context</em> concept. When you - * call libusb_init(), you are (optionally) given a context. You can then pass - * this context pointer back into future libusbx functions. - * - * In order to keep things simple for more simplistic applications, it is - * legal to pass NULL to all functions requiring a context pointer (as long as - * you're sure no other code will attempt to use libusbx from the same process). - * When you pass NULL, the default context will be used. The default context - * is created the first time a process calls libusb_init() when no other - * context is alive. Contexts are destroyed during libusb_exit(). - * - * The default context is reference-counted and can be shared. That means that - * if libusb_init(NULL) is called twice within the same process, the two - * users end up sharing the same context. The deinitialization and freeing of - * the default context will only happen when the last user calls libusb_exit(). - * In other words, the default context is created and initialized when its - * reference count goes from 0 to 1, and is deinitialized and destroyed when - * its reference count goes from 1 to 0. - * - * You may be wondering why only a subset of libusbx functions require a - * context pointer in their function definition. Internally, libusbx stores - * context pointers in other objects (e.g. libusb_device instances) and hence - * can infer the context from those objects. - */ - -/** - * @defgroup lib Library initialization/deinitialization - * This page details how to initialize and deinitialize libusbx. Initialization - * must be performed before using any libusbx functionality, and similarly you - * must not call any libusbx functions after deinitialization. - */ - -/** - * @defgroup dev Device handling and enumeration - * The functionality documented below is designed to help with the following - * operations: - * - Enumerating the USB devices currently attached to the system - * - Choosing a device to operate from your software - * - Opening and closing the chosen device - * - * \section nutshell In a nutshell... - * - * The description below really makes things sound more complicated than they - * actually are. The following sequence of function calls will be suitable - * for almost all scenarios and does not require you to have such a deep - * understanding of the resource management issues: - * \code -// discover devices -libusb_device **list; -libusb_device *found = NULL; -ssize_t cnt = libusb_get_device_list(NULL, &list); -ssize_t i = 0; -int err = 0; -if (cnt < 0) - error(); - -for (i = 0; i < cnt; i++) { - libusb_device *device = list[i]; - if (is_interesting(device)) { - found = device; - break; - } -} - -if (found) { - libusb_device_handle *handle; - - err = libusb_open(found, &handle); - if (err) - error(); - // etc -} - -libusb_free_device_list(list, 1); -\endcode - * - * The two important points: - * - You asked libusb_free_device_list() to unreference the devices (2nd - * parameter) - * - You opened the device before freeing the list and unreferencing the - * devices - * - * If you ended up with a handle, you can now proceed to perform I/O on the - * device. - * - * \section devshandles Devices and device handles - * libusbx has a concept of a USB device, represented by the - * \ref libusb_device opaque type. A device represents a USB device that - * is currently or was previously connected to the system. Using a reference - * to a device, you can determine certain information about the device (e.g. - * you can read the descriptor data). - * - * The libusb_get_device_list() function can be used to obtain a list of - * devices currently connected to the system. This is known as device - * discovery. - * - * Just because you have a reference to a device does not mean it is - * necessarily usable. The device may have been unplugged, you may not have - * permission to operate such device, or another program or driver may be - * using the device. - * - * When you've found a device that you'd like to operate, you must ask - * libusbx to open the device using the libusb_open() function. Assuming - * success, libusbx then returns you a <em>device handle</em> - * (a \ref libusb_device_handle pointer). All "real" I/O operations then - * operate on the handle rather than the original device pointer. - * - * \section devref Device discovery and reference counting - * - * Device discovery (i.e. calling libusb_get_device_list()) returns a - * freshly-allocated list of devices. The list itself must be freed when - * you are done with it. libusbx also needs to know when it is OK to free - * the contents of the list - the devices themselves. - * - * To handle these issues, libusbx provides you with two separate items: - * - A function to free the list itself - * - A reference counting system for the devices inside - * - * New devices presented by the libusb_get_device_list() function all have a - * reference count of 1. You can increase and decrease reference count using - * libusb_ref_device() and libusb_unref_device(). A device is destroyed when - * its reference count reaches 0. - * - * With the above information in mind, the process of opening a device can - * be viewed as follows: - * -# Discover devices using libusb_get_device_list(). - * -# Choose the device that you want to operate, and call libusb_open(). - * -# Unref all devices in the discovered device list. - * -# Free the discovered device list. - * - * The order is important - you must not unreference the device before - * attempting to open it, because unreferencing it may destroy the device. - * - * For convenience, the libusb_free_device_list() function includes a - * parameter to optionally unreference all the devices in the list before - * freeing the list itself. This combines steps 3 and 4 above. - * - * As an implementation detail, libusb_open() actually adds a reference to - * the device in question. This is because the device remains available - * through the handle via libusb_get_device(). The reference is deleted during - * libusb_close(). - */ - -/** @defgroup misc Miscellaneous */ - -/* we traverse usbfs without knowing how many devices we are going to find. - * so we create this discovered_devs model which is similar to a linked-list - * which grows when required. it can be freed once discovery has completed, - * eliminating the need for a list node in the libusb_device structure - * itself. */ -#define DISCOVERED_DEVICES_SIZE_STEP 8 - -static struct discovered_devs *discovered_devs_alloc(void) -{ - struct discovered_devs *ret = - malloc(sizeof(*ret) + (sizeof(void *) * DISCOVERED_DEVICES_SIZE_STEP)); - - if (ret) { - ret->len = 0; - ret->capacity = DISCOVERED_DEVICES_SIZE_STEP; - } - return ret; -} - -/* append a device to the discovered devices collection. may realloc itself, - * returning new discdevs. returns NULL on realloc failure. */ -struct discovered_devs *discovered_devs_append( - struct discovered_devs *discdevs, struct libusb_device *dev) -{ - size_t len = discdevs->len; - size_t capacity; - - /* if there is space, just append the device */ - if (len < discdevs->capacity) { - discdevs->devices[len] = libusb_ref_device(dev); - discdevs->len++; - return discdevs; - } - - /* exceeded capacity, need to grow */ - usbi_dbg("need to increase capacity"); - capacity = discdevs->capacity + DISCOVERED_DEVICES_SIZE_STEP; - discdevs = usbi_reallocf(discdevs, - sizeof(*discdevs) + (sizeof(void *) * capacity)); - if (discdevs) { - discdevs->capacity = capacity; - discdevs->devices[len] = libusb_ref_device(dev); - discdevs->len++; - } - - return discdevs; -} - -static void discovered_devs_free(struct discovered_devs *discdevs) -{ - size_t i; - - for (i = 0; i < discdevs->len; i++) - libusb_unref_device(discdevs->devices[i]); - - free(discdevs); -} - -/* Allocate a new device with a specific session ID. The returned device has - * a reference count of 1. */ -struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, - unsigned long session_id) -{ - size_t priv_size = usbi_backend->device_priv_size; - struct libusb_device *dev = calloc(1, sizeof(*dev) + priv_size); - int r; - - if (!dev) - return NULL; - - r = usbi_mutex_init(&dev->lock, NULL); - if (r) { - free(dev); - return NULL; - } - - dev->ctx = ctx; - dev->refcnt = 1; - dev->session_data = session_id; - dev->speed = LIBUSB_SPEED_UNKNOWN; - - if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { - usbi_connect_device (dev); - } - - return dev; -} - -void usbi_connect_device(struct libusb_device *dev) -{ - libusb_hotplug_message message; - ssize_t ret; - - memset(&message, 0, sizeof(message)); - message.event = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED; - message.device = dev; - dev->attached = 1; - - usbi_mutex_lock(&dev->ctx->usb_devs_lock); - list_add(&dev->list, &dev->ctx->usb_devs); - usbi_mutex_unlock(&dev->ctx->usb_devs_lock); - - /* Signal that an event has occurred for this device if we support hotplug AND - * the hotplug pipe is ready. This prevents an event from getting raised during - * initial enumeration. */ - if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) && dev->ctx->hotplug_pipe[1] > 0) { - ret = usbi_write(dev->ctx->hotplug_pipe[1], &message, sizeof(message)); - if (sizeof (message) != ret) { - usbi_err(DEVICE_CTX(dev), "error writing hotplug message"); - } - } -} - -void usbi_disconnect_device(struct libusb_device *dev) -{ - libusb_hotplug_message message; - struct libusb_context *ctx = dev->ctx; - ssize_t ret; - - memset(&message, 0, sizeof(message)); - message.event = LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT; - message.device = dev; - usbi_mutex_lock(&dev->lock); - dev->attached = 0; - usbi_mutex_unlock(&dev->lock); - - /* Signal that an event has occurred for this device if we support hotplug AND - * the hotplug pipe is ready. This prevents an event from getting raised during - * initial enumeration. libusb_handle_events will take care of dereferencing the - * device. */ - if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) && dev->ctx->hotplug_pipe[1] > 0) { - ret = usbi_write(dev->ctx->hotplug_pipe[1], &message, sizeof(message)); - if (sizeof(message) != ret) { - usbi_err(DEVICE_CTX(dev), "error writing hotplug message"); - } - } - - usbi_mutex_lock(&ctx->usb_devs_lock); - list_del(&dev->list); - usbi_mutex_unlock(&ctx->usb_devs_lock); -} - -/* Perform some final sanity checks on a newly discovered device. If this - * function fails (negative return code), the device should not be added - * to the discovered device list. */ -int usbi_sanitize_device(struct libusb_device *dev) -{ - int r; - uint8_t num_configurations; - - r = usbi_device_cache_descriptor(dev); - if (r < 0) - return r; - - num_configurations = dev->device_descriptor.bNumConfigurations; - if (num_configurations > USB_MAXCONFIG) { - usbi_err(DEVICE_CTX(dev), "too many configurations"); - return LIBUSB_ERROR_IO; - } else if (0 == num_configurations) - usbi_dbg("zero configurations, maybe an unauthorized device"); - - dev->num_configurations = num_configurations; - return 0; -} - -/* Examine libusbx's internal list of known devices, looking for one with - * a specific session ID. Returns the matching device if it was found, and - * NULL otherwise. */ -struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx, - unsigned long session_id) -{ - struct libusb_device *dev; - struct libusb_device *ret = NULL; - - usbi_mutex_lock(&ctx->usb_devs_lock); - list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) - if (dev->session_data == session_id) { - ret = dev; - break; - } - usbi_mutex_unlock(&ctx->usb_devs_lock); - - return ret; -} - -/** @ingroup dev - * Returns a list of USB devices currently attached to the system. This is - * your entry point into finding a USB device to operate. - * - * You are expected to unreference all the devices when you are done with - * them, and then free the list with libusb_free_device_list(). Note that - * libusb_free_device_list() can unref all the devices for you. Be careful - * not to unreference a device you are about to open until after you have - * opened it. - * - * This return value of this function indicates the number of devices in - * the resultant list. The list is actually one element larger, as it is - * NULL-terminated. - * - * \param ctx the context to operate on, or NULL for the default context - * \param list output location for a list of devices. Must be later freed with - * libusb_free_device_list(). - * \returns the number of devices in the outputted list, or any - * \ref libusb_error according to errors encountered by the backend. - */ -ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx, - libusb_device ***list) -{ - struct discovered_devs *discdevs = discovered_devs_alloc(); - struct libusb_device **ret; - int r = 0; - ssize_t i, len; - USBI_GET_CONTEXT(ctx); - usbi_dbg(""); - - if (!discdevs) - return LIBUSB_ERROR_NO_MEM; - - if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { - /* backend provides hotplug support */ - struct libusb_device *dev; - - if (usbi_backend->hotplug_poll) - usbi_backend->hotplug_poll(); - - usbi_mutex_lock(&ctx->usb_devs_lock); - list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) { - discdevs = discovered_devs_append(discdevs, dev); - - if (!discdevs) { - r = LIBUSB_ERROR_NO_MEM; - break; - } - } - usbi_mutex_unlock(&ctx->usb_devs_lock); - } else { - /* backend does not provide hotplug support */ - r = usbi_backend->get_device_list(ctx, &discdevs); - } - - if (r < 0) { - len = r; - goto out; - } - - /* convert discovered_devs into a list */ - len = discdevs->len; - ret = calloc(len + 1, sizeof(struct libusb_device *)); - if (!ret) { - len = LIBUSB_ERROR_NO_MEM; - goto out; - } - - ret[len] = NULL; - for (i = 0; i < len; i++) { - struct libusb_device *dev = discdevs->devices[i]; - ret[i] = libusb_ref_device(dev); - } - *list = ret; - -out: - discovered_devs_free(discdevs); - return len; -} - -/** \ingroup dev - * Frees a list of devices previously discovered using - * libusb_get_device_list(). If the unref_devices parameter is set, the - * reference count of each device in the list is decremented by 1. - * \param list the list to free - * \param unref_devices whether to unref the devices in the list - */ -void API_EXPORTED libusb_free_device_list(libusb_device **list, - int unref_devices) -{ - if (!list) - return; - - if (unref_devices) { - int i = 0; - struct libusb_device *dev; - - while ((dev = list[i++]) != NULL) - libusb_unref_device(dev); - } - free(list); -} - -/** \ingroup dev - * Get the number of the bus that a device is connected to. - * \param dev a device - * \returns the bus number - */ -uint8_t API_EXPORTED libusb_get_bus_number(libusb_device *dev) -{ - return dev->bus_number; -} - -/** \ingroup dev - * Get the number of the port that a device is connected to. - * Unless the OS does something funky, or you are hot-plugging USB extension cards, - * the port number returned by this call is usually guaranteed to be uniquely tied - * to a physical port, meaning that different devices plugged on the same physical - * port should return the same port number. - * - * But outside of this, there is no guarantee that the port number returned by this - * call will remain the same, or even match the order in which ports have been - * numbered by the HUB/HCD manufacturer. - * - * \param dev a device - * \returns the port number (0 if not available) - */ -uint8_t API_EXPORTED libusb_get_port_number(libusb_device *dev) -{ - return dev->port_number; -} - -/** \ingroup dev - * Get the list of all port numbers from root for the specified device - * - * Since version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102 - * \param dev a device - * \param port_numbers the array that should contain the port numbers - * \param port_numbers_len the maximum length of the array. As per the USB 3.0 - * specs, the current maximum limit for the depth is 7. - * \returns the number of elements filled - * \returns LIBUSB_ERROR_OVERFLOW if the array is too small - */ -int API_EXPORTED libusb_get_port_numbers(libusb_device *dev, - uint8_t* port_numbers, int port_numbers_len) -{ - int i = port_numbers_len; - - while(dev) { - // HCDs can be listed as devices and would have port #0 - // TODO: see how the other backends want to implement HCDs as parents - if (dev->port_number == 0) - break; - i--; - if (i < 0) { - usbi_warn(DEVICE_CTX(dev), - "port numbers array too small"); - return LIBUSB_ERROR_OVERFLOW; - } - port_numbers[i] = dev->port_number; - dev = dev->parent_dev; - } - memmove(port_numbers, &port_numbers[i], port_numbers_len - i); - return port_numbers_len - i; -} - -/** \ingroup dev - * Deprecated please use libusb_get_port_numbers instead. - */ -int API_EXPORTED libusb_get_port_path(libusb_context *ctx, libusb_device *dev, - uint8_t* port_numbers, uint8_t port_numbers_len) -{ - UNUSED(ctx); - - return libusb_get_port_numbers(dev, port_numbers, port_numbers_len); -} - -/** \ingroup dev - * Get the the parent from the specified device. - * \param dev a device - * \returns the device parent or NULL if not available - * You should issue a \ref libusb_get_device_list() before calling this - * function and make sure that you only access the parent before issuing - * \ref libusb_free_device_list(). The reason is that libusbx currently does - * not maintain a permanent list of device instances, and therefore can - * only guarantee that parents are fully instantiated within a - * libusb_get_device_list() - libusb_free_device_list() block. - */ -DEFAULT_VISIBILITY -libusb_device * LIBUSB_CALL libusb_get_parent(libusb_device *dev) -{ - return dev->parent_dev; -} - -/** \ingroup dev - * Get the address of the device on the bus it is connected to. - * \param dev a device - * \returns the device address - */ -uint8_t API_EXPORTED libusb_get_device_address(libusb_device *dev) -{ - return dev->device_address; -} - -/** \ingroup dev - * Get the negotiated connection speed for a device. - * \param dev a device - * \returns a \ref libusb_speed code, where LIBUSB_SPEED_UNKNOWN means that - * the OS doesn't know or doesn't support returning the negotiated speed. - */ -int API_EXPORTED libusb_get_device_speed(libusb_device *dev) -{ - return dev->speed; -} - -static const struct libusb_endpoint_descriptor *find_endpoint( - struct libusb_config_descriptor *config, unsigned char endpoint) -{ - int iface_idx; - for (iface_idx = 0; iface_idx < config->bNumInterfaces; iface_idx++) { - const struct libusb_interface *iface = &config->interface[iface_idx]; - int altsetting_idx; - - for (altsetting_idx = 0; altsetting_idx < iface->num_altsetting; - altsetting_idx++) { - const struct libusb_interface_descriptor *altsetting - = &iface->altsetting[altsetting_idx]; - int ep_idx; - - for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints; ep_idx++) { - const struct libusb_endpoint_descriptor *ep = - &altsetting->endpoint[ep_idx]; - if (ep->bEndpointAddress == endpoint) - return ep; - } - } - } - return NULL; -} - -/** \ingroup dev - * Convenience function to retrieve the wMaxPacketSize value for a particular - * endpoint in the active device configuration. - * - * This function was originally intended to be of assistance when setting up - * isochronous transfers, but a design mistake resulted in this function - * instead. It simply returns the wMaxPacketSize value without considering - * its contents. If you're dealing with isochronous transfers, you probably - * want libusb_get_max_iso_packet_size() instead. - * - * \param dev a device - * \param endpoint address of the endpoint in question - * \returns the wMaxPacketSize value - * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist - * \returns LIBUSB_ERROR_OTHER on other failure - */ -int API_EXPORTED libusb_get_max_packet_size(libusb_device *dev, - unsigned char endpoint) -{ - struct libusb_config_descriptor *config; - const struct libusb_endpoint_descriptor *ep; - int r; - - r = libusb_get_active_config_descriptor(dev, &config); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), - "could not retrieve active config descriptor"); - return LIBUSB_ERROR_OTHER; - } - - ep = find_endpoint(config, endpoint); - if (!ep) - return LIBUSB_ERROR_NOT_FOUND; - - r = ep->wMaxPacketSize; - libusb_free_config_descriptor(config); - return r; -} - -/** \ingroup dev - * Calculate the maximum packet size which a specific endpoint is capable is - * sending or receiving in the duration of 1 microframe - * - * Only the active configuration is examined. The calculation is based on the - * wMaxPacketSize field in the endpoint descriptor as described in section - * 9.6.6 in the USB 2.0 specifications. - * - * If acting on an isochronous or interrupt endpoint, this function will - * multiply the value found in bits 0:10 by the number of transactions per - * microframe (determined by bits 11:12). Otherwise, this function just - * returns the numeric value found in bits 0:10. - * - * This function is useful for setting up isochronous transfers, for example - * you might pass the return value from this function to - * libusb_set_iso_packet_lengths() in order to set the length field of every - * isochronous packet in a transfer. - * - * Since v1.0.3. - * - * \param dev a device - * \param endpoint address of the endpoint in question - * \returns the maximum packet size which can be sent/received on this endpoint - * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist - * \returns LIBUSB_ERROR_OTHER on other failure - */ -int API_EXPORTED libusb_get_max_iso_packet_size(libusb_device *dev, - unsigned char endpoint) -{ - struct libusb_config_descriptor *config; - const struct libusb_endpoint_descriptor *ep; - enum libusb_transfer_type ep_type; - uint16_t val; - int r; - - r = libusb_get_active_config_descriptor(dev, &config); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), - "could not retrieve active config descriptor"); - return LIBUSB_ERROR_OTHER; - } - - ep = find_endpoint(config, endpoint); - if (!ep) - return LIBUSB_ERROR_NOT_FOUND; - - val = ep->wMaxPacketSize; - ep_type = (enum libusb_transfer_type) (ep->bmAttributes & 0x3); - libusb_free_config_descriptor(config); - - r = val & 0x07ff; - if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS - || ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT) - r *= (1 + ((val >> 11) & 3)); - return r; -} - -/** \ingroup dev - * Increment the reference count of a device. - * \param dev the device to reference - * \returns the same device - */ -DEFAULT_VISIBILITY -libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev) -{ - usbi_mutex_lock(&dev->lock); - dev->refcnt++; - usbi_mutex_unlock(&dev->lock); - return dev; -} - -/** \ingroup dev - * Decrement the reference count of a device. If the decrement operation - * causes the reference count to reach zero, the device shall be destroyed. - * \param dev the device to unreference - */ -void API_EXPORTED libusb_unref_device(libusb_device *dev) -{ - int refcnt; - - if (!dev) - return; - - usbi_mutex_lock(&dev->lock); - refcnt = --dev->refcnt; - usbi_mutex_unlock(&dev->lock); - - if (refcnt == 0) { - usbi_dbg("destroy device %d.%d", dev->bus_number, dev->device_address); - - libusb_unref_device(dev->parent_dev); - - if (usbi_backend->destroy_device) - usbi_backend->destroy_device(dev); - - if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { - /* backend does not support hotplug */ - usbi_disconnect_device(dev); - } - - usbi_mutex_destroy(&dev->lock); - free(dev); - } -} - -/* - * Interrupt the iteration of the event handling thread, so that it picks - * up the new fd. - */ -void usbi_fd_notification(struct libusb_context *ctx) -{ - unsigned char dummy = 1; - ssize_t r; - - if (ctx == NULL) - return; - - /* record that we are messing with poll fds */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify++; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - - /* write some data on control pipe to interrupt event handlers */ - r = usbi_write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); - if (r <= 0) { - usbi_warn(ctx, "internal signalling write failed"); - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify--; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - return; - } - - /* take event handling lock */ - libusb_lock_events(ctx); - - /* read the dummy data */ - r = usbi_read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); - if (r <= 0) - usbi_warn(ctx, "internal signalling read failed"); - - /* we're done with modifying poll fds */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify--; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - - /* Release event handling lock and wake up event waiters */ - libusb_unlock_events(ctx); -} - -/** \ingroup dev - * Open a device and obtain a device handle. A handle allows you to perform - * I/O on the device in question. - * - * Internally, this function adds a reference to the device and makes it - * available to you through libusb_get_device(). This reference is removed - * during libusb_close(). - * - * This is a non-blocking function; no requests are sent over the bus. - * - * \param dev the device to open - * \param handle output location for the returned device handle pointer. Only - * populated when the return code is 0. - * \returns 0 on success - * \returns LIBUSB_ERROR_NO_MEM on memory allocation failure - * \returns LIBUSB_ERROR_ACCESS if the user has insufficient permissions - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_open(libusb_device *dev, - libusb_device_handle **handle) -{ - struct libusb_context *ctx = DEVICE_CTX(dev); - struct libusb_device_handle *_handle; - size_t priv_size = usbi_backend->device_handle_priv_size; - int r; - usbi_dbg("open %d.%d", dev->bus_number, dev->device_address); - - if (!dev->attached) { - return LIBUSB_ERROR_NO_DEVICE; - } - - _handle = malloc(sizeof(*_handle) + priv_size); - if (!_handle) - return LIBUSB_ERROR_NO_MEM; - - r = usbi_mutex_init(&_handle->lock, NULL); - if (r) { - free(_handle); - return LIBUSB_ERROR_OTHER; - } - - _handle->dev = libusb_ref_device(dev); - _handle->auto_detach_kernel_driver = 0; - _handle->claimed_interfaces = 0; - memset(&_handle->os_priv, 0, priv_size); - - r = usbi_backend->open(_handle); - if (r < 0) { - usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r); - libusb_unref_device(dev); - usbi_mutex_destroy(&_handle->lock); - free(_handle); - return r; - } - - usbi_mutex_lock(&ctx->open_devs_lock); - list_add(&_handle->list, &ctx->open_devs); - usbi_mutex_unlock(&ctx->open_devs_lock); - *handle = _handle; - - /* At this point, we want to interrupt any existing event handlers so - * that they realise the addition of the new device's poll fd. One - * example when this is desirable is if the user is running a separate - * dedicated libusbx events handling thread, which is running with a long - * or infinite timeout. We want to interrupt that iteration of the loop, - * so that it picks up the new fd, and then continues. */ - usbi_fd_notification(ctx); - - return 0; -} - -/** \ingroup dev - * Convenience function for finding a device with a particular - * <tt>idVendor</tt>/<tt>idProduct</tt> combination. This function is intended - * for those scenarios where you are using libusbx to knock up a quick test - * application - it allows you to avoid calling libusb_get_device_list() and - * worrying about traversing/freeing the list. - * - * This function has limitations and is hence not intended for use in real - * applications: if multiple devices have the same IDs it will only - * give you the first one, etc. - * - * \param ctx the context to operate on, or NULL for the default context - * \param vendor_id the idVendor value to search for - * \param product_id the idProduct value to search for - * \returns a handle for the first found device, or NULL on error or if the - * device could not be found. */ -DEFAULT_VISIBILITY -libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( - libusb_context *ctx, uint16_t vendor_id, uint16_t product_id) -{ - struct libusb_device **devs; - struct libusb_device *found = NULL; - struct libusb_device *dev; - struct libusb_device_handle *handle = NULL; - size_t i = 0; - int r; - - if (libusb_get_device_list(ctx, &devs) < 0) - return NULL; - - while ((dev = devs[i++]) != NULL) { - struct libusb_device_descriptor desc; - r = libusb_get_device_descriptor(dev, &desc); - if (r < 0) - goto out; - if (desc.idVendor == vendor_id && desc.idProduct == product_id) { - found = dev; - break; - } - } - - if (found) { - r = libusb_open(found, &handle); - if (r < 0) - handle = NULL; - } - -out: - libusb_free_device_list(devs, 1); - return handle; -} - -static void do_close(struct libusb_context *ctx, - struct libusb_device_handle *dev_handle) -{ - struct usbi_transfer *itransfer; - struct usbi_transfer *tmp; - - libusb_lock_events(ctx); - - /* remove any transfers in flight that are for this device */ - usbi_mutex_lock(&ctx->flying_transfers_lock); - - /* safe iteration because transfers may be being deleted */ - list_for_each_entry_safe(itransfer, tmp, &ctx->flying_transfers, list, struct usbi_transfer) { - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - if (transfer->dev_handle != dev_handle) - continue; - - if (!(itransfer->flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) { - usbi_err(ctx, "Device handle closed while transfer was still being processed, but the device is still connected as far as we know"); - - if (itransfer->flags & USBI_TRANSFER_CANCELLING) - usbi_warn(ctx, "A cancellation for an in-flight transfer hasn't completed but closing the device handle"); - else - usbi_err(ctx, "A cancellation hasn't even been scheduled on the transfer for which the device is closing"); - } - - /* remove from the list of in-flight transfers and make sure - * we don't accidentally use the device handle in the future - * (or that such accesses will be easily caught and identified as a crash) - */ - usbi_mutex_lock(&itransfer->lock); - list_del(&itransfer->list); - transfer->dev_handle = NULL; - usbi_mutex_unlock(&itransfer->lock); - - /* it is up to the user to free up the actual transfer struct. this is - * just making sure that we don't attempt to process the transfer after - * the device handle is invalid - */ - usbi_dbg("Removed transfer %p from the in-flight list because device handle %p closed", - transfer, dev_handle); - } - usbi_mutex_unlock(&ctx->flying_transfers_lock); - - libusb_unlock_events(ctx); - - usbi_mutex_lock(&ctx->open_devs_lock); - list_del(&dev_handle->list); - usbi_mutex_unlock(&ctx->open_devs_lock); - - usbi_backend->close(dev_handle); - libusb_unref_device(dev_handle->dev); - usbi_mutex_destroy(&dev_handle->lock); - free(dev_handle); -} - -/** \ingroup dev - * Close a device handle. Should be called on all open handles before your - * application exits. - * - * Internally, this function destroys the reference that was added by - * libusb_open() on the given device. - * - * This is a non-blocking function; no requests are sent over the bus. - * - * \param dev_handle the handle to close - */ -void API_EXPORTED libusb_close(libusb_device_handle *dev_handle) -{ - struct libusb_context *ctx; - unsigned char dummy = 1; - ssize_t r; - - if (!dev_handle) - return; - usbi_dbg(""); - - ctx = HANDLE_CTX(dev_handle); - - /* Similarly to libusb_open(), we want to interrupt all event handlers - * at this point. More importantly, we want to perform the actual close of - * the device while holding the event handling lock (preventing any other - * thread from doing event handling) because we will be removing a file - * descriptor from the polling loop. */ - - /* record that we are messing with poll fds */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify++; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - - /* write some data on control pipe to interrupt event handlers */ - r = usbi_write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); - if (r <= 0) { - usbi_warn(ctx, "internal signalling write failed, closing anyway"); - do_close(ctx, dev_handle); - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify--; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - return; - } - - /* take event handling lock */ - libusb_lock_events(ctx); - - /* read the dummy data */ - r = usbi_read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); - if (r <= 0) - usbi_warn(ctx, "internal signalling read failed, closing anyway"); - - /* Close the device */ - do_close(ctx, dev_handle); - - /* we're done with modifying poll fds */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify--; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - - /* Release event handling lock and wake up event waiters */ - libusb_unlock_events(ctx); -} - -/** \ingroup dev - * Get the underlying device for a handle. This function does not modify - * the reference count of the returned device, so do not feel compelled to - * unreference it when you are done. - * \param dev_handle a device handle - * \returns the underlying device - */ -DEFAULT_VISIBILITY -libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle) -{ - return dev_handle->dev; -} - -/** \ingroup dev - * Determine the bConfigurationValue of the currently active configuration. - * - * You could formulate your own control request to obtain this information, - * but this function has the advantage that it may be able to retrieve the - * information from operating system caches (no I/O involved). - * - * If the OS does not cache this information, then this function will block - * while a control transfer is submitted to retrieve the information. - * - * This function will return a value of 0 in the <tt>config</tt> output - * parameter if the device is in unconfigured state. - * - * \param dev a device handle - * \param config output location for the bConfigurationValue of the active - * configuration (only valid for return code 0) - * \returns 0 on success - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev, - int *config) -{ - int r = LIBUSB_ERROR_NOT_SUPPORTED; - - usbi_dbg(""); - if (usbi_backend->get_configuration) - r = usbi_backend->get_configuration(dev, config); - - if (r == LIBUSB_ERROR_NOT_SUPPORTED) { - uint8_t tmp = 0; - usbi_dbg("falling back to control message"); - r = libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, - LIBUSB_REQUEST_GET_CONFIGURATION, 0, 0, &tmp, 1, 1000); - if (r == 0) { - usbi_err(HANDLE_CTX(dev), "zero bytes returned in ctrl transfer?"); - r = LIBUSB_ERROR_IO; - } else if (r == 1) { - r = 0; - *config = tmp; - } else { - usbi_dbg("control failed, error %d", r); - } - } - - if (r == 0) - usbi_dbg("active config %d", *config); - - return r; -} - -/** \ingroup dev - * Set the active configuration for a device. - * - * The operating system may or may not have already set an active - * configuration on the device. It is up to your application to ensure the - * correct configuration is selected before you attempt to claim interfaces - * and perform other operations. - * - * If you call this function on a device already configured with the selected - * configuration, then this function will act as a lightweight device reset: - * it will issue a SET_CONFIGURATION request using the current configuration, - * causing most USB-related device state to be reset (altsetting reset to zero, - * endpoint halts cleared, toggles reset). - * - * You cannot change/reset configuration if your application has claimed - * interfaces. It is advised to set the desired configuration before claiming - * interfaces. - * - * Alternatively you can call libusb_release_interface() first. Note if you - * do things this way you must ensure that auto_detach_kernel_driver for - * <tt>dev</tt> is 0, otherwise the kernel driver will be re-attached when you - * release the interface(s). - * - * You cannot change/reset configuration if other applications or drivers have - * claimed interfaces. - * - * A configuration value of -1 will put the device in unconfigured state. - * The USB specifications state that a configuration value of 0 does this, - * however buggy devices exist which actually have a configuration 0. - * - * You should always use this function rather than formulating your own - * SET_CONFIGURATION control request. This is because the underlying operating - * system needs to know when such changes happen. - * - * This is a blocking function. - * - * \param dev a device handle - * \param configuration the bConfigurationValue of the configuration you - * wish to activate, or -1 if you wish to put the device in unconfigured state - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the requested configuration does not exist - * \returns LIBUSB_ERROR_BUSY if interfaces are currently claimed - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - * \see libusb_set_auto_detach_kernel_driver() - */ -int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev, - int configuration) -{ - usbi_dbg("configuration %d", configuration); - return usbi_backend->set_configuration(dev, configuration); -} - -/** \ingroup dev - * Claim an interface on a given device handle. You must claim the interface - * you wish to use before you can perform I/O on any of its endpoints. - * - * It is legal to attempt to claim an already-claimed interface, in which - * case libusbx just returns 0 without doing anything. - * - * If auto_detach_kernel_driver is set to 1 for <tt>dev</tt>, the kernel driver - * will be detached if necessary, on failure the detach error is returned. - * - * Claiming of interfaces is a purely logical operation; it does not cause - * any requests to be sent over the bus. Interface claiming is used to - * instruct the underlying operating system that your application wishes - * to take ownership of the interface. - * - * This is a non-blocking function. - * - * \param dev a device handle - * \param interface_number the <tt>bInterfaceNumber</tt> of the interface you - * wish to claim - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the requested interface does not exist - * \returns LIBUSB_ERROR_BUSY if another program or driver has claimed the - * interface - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns a LIBUSB_ERROR code on other failure - * \see libusb_set_auto_detach_kernel_driver() - */ -int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev, - int interface_number) -{ - int r = 0; - - usbi_dbg("interface %d", interface_number); - if (interface_number >= USB_MAXINTERFACES) - return LIBUSB_ERROR_INVALID_PARAM; - - if (!dev->dev->attached) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_mutex_lock(&dev->lock); - if (dev->claimed_interfaces & (1 << interface_number)) - goto out; - - r = usbi_backend->claim_interface(dev, interface_number); - if (r == 0) - dev->claimed_interfaces |= 1 << interface_number; - -out: - usbi_mutex_unlock(&dev->lock); - return r; -} - -/** \ingroup dev - * Release an interface previously claimed with libusb_claim_interface(). You - * should release all claimed interfaces before closing a device handle. - * - * This is a blocking function. A SET_INTERFACE control request will be sent - * to the device, resetting interface state to the first alternate setting. - * - * If auto_detach_kernel_driver is set to 1 for <tt>dev</tt>, the kernel - * driver will be re-attached after releasing the interface. - * - * \param dev a device handle - * \param interface_number the <tt>bInterfaceNumber</tt> of the - * previously-claimed interface - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the interface was not claimed - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - * \see libusb_set_auto_detach_kernel_driver() - */ -int API_EXPORTED libusb_release_interface(libusb_device_handle *dev, - int interface_number) -{ - int r; - - usbi_dbg("interface %d", interface_number); - if (interface_number >= USB_MAXINTERFACES) - return LIBUSB_ERROR_INVALID_PARAM; - - usbi_mutex_lock(&dev->lock); - if (!(dev->claimed_interfaces & (1 << interface_number))) { - r = LIBUSB_ERROR_NOT_FOUND; - goto out; - } - - r = usbi_backend->release_interface(dev, interface_number); - if (r == 0) - dev->claimed_interfaces &= ~(1 << interface_number); - -out: - usbi_mutex_unlock(&dev->lock); - return r; -} - -/** \ingroup dev - * Activate an alternate setting for an interface. The interface must have - * been previously claimed with libusb_claim_interface(). - * - * You should always use this function rather than formulating your own - * SET_INTERFACE control request. This is because the underlying operating - * system needs to know when such changes happen. - * - * This is a blocking function. - * - * \param dev a device handle - * \param interface_number the <tt>bInterfaceNumber</tt> of the - * previously-claimed interface - * \param alternate_setting the <tt>bAlternateSetting</tt> of the alternate - * setting to activate - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the interface was not claimed, or the - * requested alternate setting does not exist - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev, - int interface_number, int alternate_setting) -{ - usbi_dbg("interface %d altsetting %d", - interface_number, alternate_setting); - if (interface_number >= USB_MAXINTERFACES) - return LIBUSB_ERROR_INVALID_PARAM; - - usbi_mutex_lock(&dev->lock); - if (!dev->dev->attached) { - usbi_mutex_unlock(&dev->lock); - return LIBUSB_ERROR_NO_DEVICE; - } - - if (!(dev->claimed_interfaces & (1 << interface_number))) { - usbi_mutex_unlock(&dev->lock); - return LIBUSB_ERROR_NOT_FOUND; - } - usbi_mutex_unlock(&dev->lock); - - return usbi_backend->set_interface_altsetting(dev, interface_number, - alternate_setting); -} - -/** \ingroup dev - * Clear the halt/stall condition for an endpoint. Endpoints with halt status - * are unable to receive or transmit data until the halt condition is stalled. - * - * You should cancel all pending transfers before attempting to clear the halt - * condition. - * - * This is a blocking function. - * - * \param dev a device handle - * \param endpoint the endpoint to clear halt status - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_clear_halt(libusb_device_handle *dev, - unsigned char endpoint) -{ - usbi_dbg("endpoint %x", endpoint); - if (!dev->dev->attached) - return LIBUSB_ERROR_NO_DEVICE; - - return usbi_backend->clear_halt(dev, endpoint); -} - -/** \ingroup dev - * Perform a USB port reset to reinitialize a device. The system will attempt - * to restore the previous configuration and alternate settings after the - * reset has completed. - * - * If the reset fails, the descriptors change, or the previous state cannot be - * restored, the device will appear to be disconnected and reconnected. This - * means that the device handle is no longer valid (you should close it) and - * rediscover the device. A return code of LIBUSB_ERROR_NOT_FOUND indicates - * when this is the case. - * - * This is a blocking function which usually incurs a noticeable delay. - * - * \param dev a handle of the device to reset - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the - * device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_reset_device(libusb_device_handle *dev) -{ - usbi_dbg(""); - if (!dev->dev->attached) - return LIBUSB_ERROR_NO_DEVICE; - - return usbi_backend->reset_device(dev); -} - -/** \ingroup dev - * Determine if a kernel driver is active on an interface. If a kernel driver - * is active, you cannot claim the interface, and libusbx will be unable to - * perform I/O. - * - * This functionality is not available on Windows. - * - * \param dev a device handle - * \param interface_number the interface to check - * \returns 0 if no kernel driver is active - * \returns 1 if a kernel driver is active - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality - * is not available - * \returns another LIBUSB_ERROR code on other failure - * \see libusb_detach_kernel_driver() - */ -int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev, - int interface_number) -{ - usbi_dbg("interface %d", interface_number); - - if (!dev->dev->attached) - return LIBUSB_ERROR_NO_DEVICE; - - if (usbi_backend->kernel_driver_active) - return usbi_backend->kernel_driver_active(dev, interface_number); - else - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -/** \ingroup dev - * Detach a kernel driver from an interface. If successful, you will then be - * able to claim the interface and perform I/O. - * - * This functionality is not available on Darwin or Windows. - * - * Note that libusbx itself also talks to the device through a special kernel - * driver, if this driver is already attached to the device, this call will - * not detach it and return LIBUSB_ERROR_NOT_FOUND. - * - * \param dev a device handle - * \param interface_number the interface to detach the driver from - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * \returns LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality - * is not available - * \returns another LIBUSB_ERROR code on other failure - * \see libusb_kernel_driver_active() - */ -int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev, - int interface_number) -{ - usbi_dbg("interface %d", interface_number); - - if (!dev->dev->attached) - return LIBUSB_ERROR_NO_DEVICE; - - if (usbi_backend->detach_kernel_driver) - return usbi_backend->detach_kernel_driver(dev, interface_number); - else - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -/** \ingroup dev - * Re-attach an interface's kernel driver, which was previously detached - * using libusb_detach_kernel_driver(). This call is only effective on - * Linux and returns LIBUSB_ERROR_NOT_SUPPORTED on all other platforms. - * - * This functionality is not available on Darwin or Windows. - * - * \param dev a device handle - * \param interface_number the interface to attach the driver from - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * \returns LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality - * is not available - * \returns LIBUSB_ERROR_BUSY if the driver cannot be attached because the - * interface is claimed by a program or driver - * \returns another LIBUSB_ERROR code on other failure - * \see libusb_kernel_driver_active() - */ -int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev, - int interface_number) -{ - usbi_dbg("interface %d", interface_number); - - if (!dev->dev->attached) - return LIBUSB_ERROR_NO_DEVICE; - - if (usbi_backend->attach_kernel_driver) - return usbi_backend->attach_kernel_driver(dev, interface_number); - else - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -/** \ingroup dev - * Enable/disable libusbx's automatic kernel driver detachment. When this is - * enabled libusbx will automatically detach the kernel driver on an interface - * when claiming the interface, and attach it when releasing the interface. - * - * Automatic kernel driver detachment is disabled on newly opened device - * handles by default. - * - * On platforms which do not have LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER - * this function will return LIBUSB_ERROR_NOT_SUPPORTED, and libusbx will - * continue as if this function was never called. - * - * \param dev a device handle - * \param enable whether to enable or disable auto kernel driver detachment - * - * \returns LIBUSB_SUCCESS on success - * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality - * is not available - * \see libusb_claim_interface() - * \see libusb_release_interface() - * \see libusb_set_configuration() - */ -int API_EXPORTED libusb_set_auto_detach_kernel_driver( - libusb_device_handle *dev, int enable) -{ - if (!(usbi_backend->caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER)) - return LIBUSB_ERROR_NOT_SUPPORTED; - - dev->auto_detach_kernel_driver = enable; - return LIBUSB_SUCCESS; -} - -/** \ingroup lib - * Set log message verbosity. - * - * The default level is LIBUSB_LOG_LEVEL_NONE, which means no messages are ever - * printed. If you choose to increase the message verbosity level, ensure - * that your application does not close the stdout/stderr file descriptors. - * - * You are advised to use level LIBUSB_LOG_LEVEL_WARNING. libusbx is conservative - * with its message logging and most of the time, will only log messages that - * explain error conditions and other oddities. This will help you debug - * your software. - * - * If the LIBUSB_DEBUG environment variable was set when libusbx was - * initialized, this function does nothing: the message verbosity is fixed - * to the value in the environment variable. - * - * If libusbx was compiled without any message logging, this function does - * nothing: you'll never get any messages. - * - * If libusbx was compiled with verbose debug message logging, this function - * does nothing: you'll always get messages from all levels. - * - * \param ctx the context to operate on, or NULL for the default context - * \param level debug level to set - */ -void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level) -{ - USBI_GET_CONTEXT(ctx); - if (!ctx->debug_fixed) - ctx->debug = level; -} - -/** \ingroup lib - * Initialize libusb. This function must be called before calling any other - * libusbx function. - * - * If you do not provide an output location for a context pointer, a default - * context will be created. If there was already a default context, it will - * be reused (and nothing will be initialized/reinitialized). - * - * \param context Optional output location for context pointer. - * Only valid on return code 0. - * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \see contexts - */ -int API_EXPORTED libusb_init(libusb_context **context) -{ - struct libusb_device *dev, *next; - char *dbg = getenv("LIBUSB_DEBUG"); - struct libusb_context *ctx; - static int first_init = 1; - int r = 0; - - usbi_mutex_static_lock(&default_context_lock); - - if (!timestamp_origin.tv_sec) { - usbi_gettimeofday(×tamp_origin, NULL); - } - - if (!context && usbi_default_context) { - usbi_dbg("reusing default context"); - default_context_refcnt++; - usbi_mutex_static_unlock(&default_context_lock); - return 0; - } - - ctx = calloc(1, sizeof(*ctx)); - if (!ctx) { - r = LIBUSB_ERROR_NO_MEM; - goto err_unlock; - } - -#ifdef ENABLE_DEBUG_LOGGING - ctx->debug = LIBUSB_LOG_LEVEL_DEBUG; -#endif - - if (dbg) { - ctx->debug = atoi(dbg); - if (ctx->debug) - ctx->debug_fixed = 1; - } - - /* default context should be initialized before calling usbi_dbg */ - if (!usbi_default_context) { - usbi_default_context = ctx; - default_context_refcnt++; - usbi_dbg("created default context"); - } - - usbi_dbg("libusbx v%d.%d.%d.%d", libusb_version_internal.major, libusb_version_internal.minor, - libusb_version_internal.micro, libusb_version_internal.nano); - - usbi_mutex_init(&ctx->usb_devs_lock, NULL); - usbi_mutex_init(&ctx->open_devs_lock, NULL); - usbi_mutex_init(&ctx->hotplug_cbs_lock, NULL); - list_init(&ctx->usb_devs); - list_init(&ctx->open_devs); - list_init(&ctx->hotplug_cbs); - - usbi_mutex_static_lock(&active_contexts_lock); - if (first_init) { - first_init = 0; - list_init (&active_contexts_list); - } - list_add (&ctx->list, &active_contexts_list); - usbi_mutex_static_unlock(&active_contexts_lock); - - if (usbi_backend->init) { - r = usbi_backend->init(ctx); - if (r) - goto err_free_ctx; - } - - r = usbi_io_init(ctx); - if (r < 0) - goto err_backend_exit; - - usbi_mutex_static_unlock(&default_context_lock); - - if (context) - *context = ctx; - - return 0; - -err_backend_exit: - if (usbi_backend->exit) - usbi_backend->exit(); -err_free_ctx: - if (ctx == usbi_default_context) - usbi_default_context = NULL; - - usbi_mutex_destroy(&ctx->open_devs_lock); - usbi_mutex_destroy(&ctx->usb_devs_lock); - usbi_mutex_destroy(&ctx->hotplug_cbs_lock); - - usbi_mutex_static_lock(&active_contexts_lock); - list_del (&ctx->list); - usbi_mutex_static_unlock(&active_contexts_lock); - - usbi_mutex_lock(&ctx->usb_devs_lock); - list_for_each_entry_safe(dev, next, &ctx->usb_devs, list, struct libusb_device) { - list_del(&dev->list); - libusb_unref_device(dev); - } - usbi_mutex_unlock(&ctx->usb_devs_lock); - - free(ctx); -err_unlock: - usbi_mutex_static_unlock(&default_context_lock); - return r; -} - -/** \ingroup lib - * Deinitialize libusb. Should be called after closing all open devices and - * before your application terminates. - * \param ctx the context to deinitialize, or NULL for the default context - */ -void API_EXPORTED libusb_exit(struct libusb_context *ctx) -{ - struct libusb_device *dev, *next; - - usbi_dbg(""); - USBI_GET_CONTEXT(ctx); - - /* if working with default context, only actually do the deinitialization - * if we're the last user */ - usbi_mutex_static_lock(&default_context_lock); - if (ctx == usbi_default_context) { - if (--default_context_refcnt > 0) { - usbi_dbg("not destroying default context"); - usbi_mutex_static_unlock(&default_context_lock); - return; - } - usbi_dbg("destroying default context"); - usbi_default_context = NULL; - } - usbi_mutex_static_unlock(&default_context_lock); - - usbi_mutex_static_lock(&active_contexts_lock); - list_del (&ctx->list); - usbi_mutex_static_unlock(&active_contexts_lock); - - if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { - usbi_hotplug_deregister_all(ctx); - usbi_mutex_lock(&ctx->usb_devs_lock); - list_for_each_entry_safe(dev, next, &ctx->usb_devs, list, struct libusb_device) { - list_del(&dev->list); - libusb_unref_device(dev); - } - usbi_mutex_unlock(&ctx->usb_devs_lock); - } - - /* a few sanity checks. don't bother with locking because unless - * there is an application bug, nobody will be accessing these. */ - if (!list_empty(&ctx->usb_devs)) - usbi_warn(ctx, "some libusb_devices were leaked"); - if (!list_empty(&ctx->open_devs)) - usbi_warn(ctx, "application left some devices open"); - - usbi_io_exit(ctx); - if (usbi_backend->exit) - usbi_backend->exit(); - - usbi_mutex_destroy(&ctx->open_devs_lock); - usbi_mutex_destroy(&ctx->usb_devs_lock); - usbi_mutex_destroy(&ctx->hotplug_cbs_lock); - free(ctx); -} - -/** \ingroup misc - * Check at runtime if the loaded library has a given capability. - * This call should be performed after \ref libusb_init(), to ensure the - * backend has updated its capability set. - * - * \param capability the \ref libusb_capability to check for - * \returns nonzero if the running library has the capability, 0 otherwise - */ -int API_EXPORTED libusb_has_capability(uint32_t capability) -{ - switch (capability) { - case LIBUSB_CAP_HAS_CAPABILITY: - return 1; - case LIBUSB_CAP_HAS_HOTPLUG: - return !(usbi_backend->get_device_list); - case LIBUSB_CAP_HAS_HID_ACCESS: - return (usbi_backend->caps & USBI_CAP_HAS_HID_ACCESS); - case LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER: - return (usbi_backend->caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER); - } - return 0; -} - -/* this is defined in libusbi.h if needed */ -#ifdef LIBUSB_GETTIMEOFDAY_WIN32 -/* - * gettimeofday - * Implementation according to: - * The Open Group Base Specifications Issue 6 - * IEEE Std 1003.1, 2004 Edition - */ - -/* - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Contributed by: - * Danny Smith <dannysmith@users.sourceforge.net> - */ - -/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ -#define _W32_FT_OFFSET (116444736000000000) - -int usbi_gettimeofday(struct timeval *tp, void *tzp) -{ - union { - unsigned __int64 ns100; /* Time since 1 Jan 1601, in 100ns units */ - FILETIME ft; - } _now; - UNUSED(tzp); - - if(tp) { -#if defined(OS_WINCE) - SYSTEMTIME st; - GetSystemTime(&st); - SystemTimeToFileTime(&st, &_now.ft); -#else - GetSystemTimeAsFileTime (&_now.ft); -#endif - tp->tv_usec=(long)((_now.ns100 / 10) % 1000000 ); - tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000); - } - /* Always return 0 as per Open Group Base Specifications Issue 6. - Do not set errno on error. */ - return 0; -} -#endif - -static void usbi_log_str(struct libusb_context *ctx, const char * str) -{ - UNUSED(ctx); - fputs(str, stderr); -} - -void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, - const char *function, const char *format, va_list args) -{ - const char *prefix = ""; - char buf[USBI_MAX_LOG_LEN]; - struct timeval now; - int global_debug, header_len, text_len; - static int has_debug_header_been_displayed = 0; - -#ifdef ENABLE_DEBUG_LOGGING - global_debug = 1; - UNUSED(ctx); -#else - USBI_GET_CONTEXT(ctx); - if (ctx == NULL) - return; - global_debug = (ctx->debug == LIBUSB_LOG_LEVEL_DEBUG); - if (!ctx->debug) - return; - if (level == LIBUSB_LOG_LEVEL_WARNING && ctx->debug < LIBUSB_LOG_LEVEL_WARNING) - return; - if (level == LIBUSB_LOG_LEVEL_INFO && ctx->debug < LIBUSB_LOG_LEVEL_INFO) - return; - if (level == LIBUSB_LOG_LEVEL_DEBUG && ctx->debug < LIBUSB_LOG_LEVEL_DEBUG) - return; -#endif - -#ifdef __ANDROID__ - int prio; - switch (level) { - case LOG_LEVEL_INFO: - prio = ANDROID_LOG_INFO; - break; - case LOG_LEVEL_WARNING: - prio = ANDROID_LOG_WARN; - break; - case LOG_LEVEL_ERROR: - prio = ANDROID_LOG_ERROR; - break; - case LOG_LEVEL_DEBUG: - prio = ANDROID_LOG_DEBUG; - break; - default: - prio = ANDROID_LOG_UNKNOWN; - break; - } - - __android_log_vprint(prio, "LibUsb", format, args); -#else - usbi_gettimeofday(&now, NULL); - if ((global_debug) && (!has_debug_header_been_displayed)) { - has_debug_header_been_displayed = 1; - usbi_log_str(ctx, "[timestamp] [threadID] facility level [function call] <message>\n"); - usbi_log_str(ctx, "--------------------------------------------------------------------------------\n"); - } - if (now.tv_usec < timestamp_origin.tv_usec) { - now.tv_sec--; - now.tv_usec += 1000000; - } - now.tv_sec -= timestamp_origin.tv_sec; - now.tv_usec -= timestamp_origin.tv_usec; - - switch (level) { - case LIBUSB_LOG_LEVEL_INFO: - prefix = "info"; - break; - case LIBUSB_LOG_LEVEL_WARNING: - prefix = "warning"; - break; - case LIBUSB_LOG_LEVEL_ERROR: - prefix = "error"; - break; - case LIBUSB_LOG_LEVEL_DEBUG: - prefix = "debug"; - break; - case LIBUSB_LOG_LEVEL_NONE: - break; - default: - prefix = "unknown"; - break; - } - - if (global_debug) { - header_len = snprintf(buf, sizeof(buf), - "[%2d.%06d] [%08x] libusbx: %s [%s] ", - (int)now.tv_sec, (int)now.tv_usec, usbi_get_tid(), prefix, function); - } else { - header_len = snprintf(buf, sizeof(buf), - "libusbx: %s [%s] ", prefix, function); - } - - if (header_len < 0 || header_len >= sizeof(buf)) { - /* Somehow snprintf failed to write to the buffer, - * remove the header so something useful is output. */ - header_len = 0; - } - /* Make sure buffer is NUL terminated */ - buf[header_len] = '\0'; - text_len = vsnprintf(buf + header_len, sizeof(buf) - header_len, - format, args); - if (text_len < 0 || text_len + header_len >= sizeof(buf)) { - /* Truncated log output. On some platforms a -1 return value means - * that the output was truncated. */ - text_len = sizeof(buf) - header_len; - } - if (header_len + text_len + sizeof(USBI_LOG_LINE_END) >= sizeof(buf)) { - /* Need to truncate the text slightly to fit on the terminator. */ - text_len -= (header_len + text_len + sizeof(USBI_LOG_LINE_END)) - sizeof(buf); - } - strcpy(buf + header_len + text_len, USBI_LOG_LINE_END); - - usbi_log_str(ctx, buf); -#endif -} - -void usbi_log(struct libusb_context *ctx, enum libusb_log_level level, - const char *function, const char *format, ...) -{ - va_list args; - - va_start (args, format); - usbi_log_v(ctx, level, function, format, args); - va_end (args); -} - -/** \ingroup misc - * Returns a constant NULL-terminated string with the ASCII name of a libusbx - * error or transfer status code. The caller must not free() the returned - * string. - * - * \param error_code The \ref libusb_error or libusb_transfer_status code to - * return the name of. - * \returns The error name, or the string **UNKNOWN** if the value of - * error_code is not a known error / status code. - */ -DEFAULT_VISIBILITY const char * LIBUSB_CALL libusb_error_name(int error_code) -{ - switch (error_code) { - case LIBUSB_ERROR_IO: - return "LIBUSB_ERROR_IO"; - case LIBUSB_ERROR_INVALID_PARAM: - return "LIBUSB_ERROR_INVALID_PARAM"; - case LIBUSB_ERROR_ACCESS: - return "LIBUSB_ERROR_ACCESS"; - case LIBUSB_ERROR_NO_DEVICE: - return "LIBUSB_ERROR_NO_DEVICE"; - case LIBUSB_ERROR_NOT_FOUND: - return "LIBUSB_ERROR_NOT_FOUND"; - case LIBUSB_ERROR_BUSY: - return "LIBUSB_ERROR_BUSY"; - case LIBUSB_ERROR_TIMEOUT: - return "LIBUSB_ERROR_TIMEOUT"; - case LIBUSB_ERROR_OVERFLOW: - return "LIBUSB_ERROR_OVERFLOW"; - case LIBUSB_ERROR_PIPE: - return "LIBUSB_ERROR_PIPE"; - case LIBUSB_ERROR_INTERRUPTED: - return "LIBUSB_ERROR_INTERRUPTED"; - case LIBUSB_ERROR_NO_MEM: - return "LIBUSB_ERROR_NO_MEM"; - case LIBUSB_ERROR_NOT_SUPPORTED: - return "LIBUSB_ERROR_NOT_SUPPORTED"; - case LIBUSB_ERROR_OTHER: - return "LIBUSB_ERROR_OTHER"; - - case LIBUSB_TRANSFER_ERROR: - return "LIBUSB_TRANSFER_ERROR"; - case LIBUSB_TRANSFER_TIMED_OUT: - return "LIBUSB_TRANSFER_TIMED_OUT"; - case LIBUSB_TRANSFER_CANCELLED: - return "LIBUSB_TRANSFER_CANCELLED"; - case LIBUSB_TRANSFER_STALL: - return "LIBUSB_TRANSFER_STALL"; - case LIBUSB_TRANSFER_NO_DEVICE: - return "LIBUSB_TRANSFER_NO_DEVICE"; - case LIBUSB_TRANSFER_OVERFLOW: - return "LIBUSB_TRANSFER_OVERFLOW"; - - case 0: - return "LIBUSB_SUCCESS / LIBUSB_TRANSFER_COMPLETED"; - default: - return "**UNKNOWN**"; - } -} - -/** \ingroup misc - * Returns a pointer to const struct libusb_version with the version - * (major, minor, micro, nano and rc) of the running library. - */ -DEFAULT_VISIBILITY -const struct libusb_version * LIBUSB_CALL libusb_get_version(void) -{ - return &libusb_version_internal; -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/descriptor.c b/src/3rd_party-static/libusbx-1.0.16/libusb/descriptor.c deleted file mode 100644 index ba6d1467d7..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/descriptor.c +++ /dev/null @@ -1,1197 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */ -/* - * 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 - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <errno.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#include "libusbi.h" - -#define DESC_HEADER_LENGTH 2 -#define DEVICE_DESC_LENGTH 18 -#define CONFIG_DESC_LENGTH 9 -#define INTERFACE_DESC_LENGTH 9 -#define ENDPOINT_DESC_LENGTH 7 -#define ENDPOINT_AUDIO_DESC_LENGTH 9 - -/** @defgroup desc USB descriptors - * This page details how to examine the various standard USB descriptors - * for detected devices - */ - -/* set host_endian if the w values are already in host endian format, - * as opposed to bus endian. */ -int usbi_parse_descriptor(const unsigned char *source, const char *descriptor, - void *dest, int host_endian) -{ - const unsigned char *sp = source; - unsigned char *dp = dest; - uint16_t w; - const char *cp; - uint32_t d; - - for (cp = descriptor; *cp; cp++) { - switch (*cp) { - case 'b': /* 8-bit byte */ - *dp++ = *sp++; - break; - case 'w': /* 16-bit word, convert from little endian to CPU */ - dp += ((uintptr_t)dp & 1); /* Align to word boundary */ - - if (host_endian) { - memcpy(dp, sp, 2); - } else { - w = (sp[1] << 8) | sp[0]; - *((uint16_t *)dp) = w; - } - sp += 2; - dp += 2; - break; - case 'd': /* 32-bit word, convert from little endian to CPU */ - dp += ((uintptr_t)dp & 1); /* Align to word boundary */ - - if (host_endian) { - memcpy(dp, sp, 4); - } else { - d = (sp[3] << 24) | (sp[2] << 16) | - (sp[1] << 8) | sp[0]; - *((uint32_t *)dp) = d; - } - sp += 4; - dp += 4; - break; - case 'u': /* 16 byte UUID */ - memcpy(dp, sp, 16); - sp += 16; - dp += 16; - break; - } - } - - return (int) (sp - source); -} - -static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint) -{ - if (endpoint->extra) - free((unsigned char *) endpoint->extra); -} - -static int parse_endpoint(struct libusb_context *ctx, - struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer, - int size, int host_endian) -{ - struct usb_descriptor_header header; - unsigned char *extra; - unsigned char *begin; - int parsed = 0; - int len; - - 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) { - usbi_err(ctx, "unexpected descriptor %x (expected %x)", - header.bDescriptorType, LIBUSB_DT_ENDPOINT); - 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) - usbi_parse_descriptor(buffer, "bbbbwbbb", endpoint, host_endian); - else if (header.bLength >= ENDPOINT_DESC_LENGTH) - 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; - size -= header.bLength; - parsed += header.bLength; - - /* Skip over the rest of the Class Specific or Vendor Specific */ - /* descriptors */ - begin = buffer; - while (size >= DESC_HEADER_LENGTH) { - usbi_parse_descriptor(buffer, "bb", &header, 0); - if (header.bLength < 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 ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || - (header.bDescriptorType == LIBUSB_DT_INTERFACE) || - (header.bDescriptorType == LIBUSB_DT_CONFIG) || - (header.bDescriptorType == LIBUSB_DT_DEVICE)) - break; - - usbi_dbg("skipping descriptor %x", header.bDescriptorType); - buffer += header.bLength; - size -= header.bLength; - parsed += header.bLength; - } - - /* Copy any unknown descriptors into a storage area for drivers */ - /* to later parse */ - len = (int)(buffer - begin); - if (!len) { - endpoint->extra = NULL; - endpoint->extra_length = 0; - return parsed; - } - - extra = malloc(len); - endpoint->extra = extra; - if (!extra) { - endpoint->extra_length = 0; - return LIBUSB_ERROR_NO_MEM; - } - - memcpy(extra, begin, len); - endpoint->extra_length = len; - - return parsed; -} - -static void clear_interface(struct libusb_interface *usb_interface) -{ - int i; - int j; - - if (usb_interface->altsetting) { - for (i = 0; i < usb_interface->num_altsetting; i++) { - struct libusb_interface_descriptor *ifp = - (struct libusb_interface_descriptor *) - usb_interface->altsetting + i; - if (ifp->extra) - free((void *) ifp->extra); - if (ifp->endpoint) { - for (j = 0; j < ifp->bNumEndpoints; j++) - clear_endpoint((struct libusb_endpoint_descriptor *) - ifp->endpoint + j); - free((void *) ifp->endpoint); - } - } - free((void *) usb_interface->altsetting); - usb_interface->altsetting = NULL; - } - -} - -static int parse_interface(libusb_context *ctx, - struct libusb_interface *usb_interface, unsigned char *buffer, int size, - int host_endian) -{ - int i; - int len; - int r; - int parsed = 0; - int interface_number = -1; - size_t tmp; - struct usb_descriptor_header header; - struct libusb_interface_descriptor *ifp; - unsigned char *begin; - - usb_interface->num_altsetting = 0; - - while (size >= INTERFACE_DESC_LENGTH) { - struct libusb_interface_descriptor *altsetting = - (struct libusb_interface_descriptor *) usb_interface->altsetting; - altsetting = usbi_reallocf(altsetting, - sizeof(struct libusb_interface_descriptor) * - (usb_interface->num_altsetting + 1)); - if (!altsetting) { - r = LIBUSB_ERROR_NO_MEM; - goto err; - } - usb_interface->altsetting = altsetting; - - ifp = altsetting + usb_interface->num_altsetting; - 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_length = 0; - ifp->endpoint = NULL; - - if (interface_number == -1) - interface_number = ifp->bInterfaceNumber; - - /* Skip over the interface */ - buffer += ifp->bLength; - parsed += ifp->bLength; - size -= ifp->bLength; - - begin = buffer; - - /* Skip over any interface, class or vendor descriptors */ - while (size >= DESC_HEADER_LENGTH) { - usbi_parse_descriptor(buffer, "bb", &header, 0); - if (header.bLength < DESC_HEADER_LENGTH) { - usbi_err(ctx, - "invalid extra intf desc len (%d)", - header.bLength); - r = LIBUSB_ERROR_IO; - 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 ((header.bDescriptorType == LIBUSB_DT_INTERFACE) || - (header.bDescriptorType == LIBUSB_DT_ENDPOINT) || - (header.bDescriptorType == LIBUSB_DT_CONFIG) || - (header.bDescriptorType == LIBUSB_DT_DEVICE)) - break; - - buffer += header.bLength; - parsed += header.bLength; - size -= header.bLength; - } - - /* Copy any unknown descriptors into a storage area for */ - /* drivers to later parse */ - len = (int)(buffer - begin); - if (len) { - ifp->extra = malloc(len); - if (!ifp->extra) { - r = LIBUSB_ERROR_NO_MEM; - goto err; - } - memcpy((unsigned char *) ifp->extra, begin, len); - ifp->extra_length = len; - } - - if (ifp->bNumEndpoints > 0) { - struct libusb_endpoint_descriptor *endpoint; - tmp = ifp->bNumEndpoints * sizeof(struct libusb_endpoint_descriptor); - endpoint = malloc(tmp); - ifp->endpoint = endpoint; - if (!endpoint) { - r = LIBUSB_ERROR_NO_MEM; - goto err; - } - - memset(endpoint, 0, tmp); - for (i = 0; i < ifp->bNumEndpoints; i++) { - r = parse_endpoint(ctx, endpoint + i, buffer, size, - host_endian); - if (r < 0) - goto err; - if (r == 0) { - ifp->bNumEndpoints = (uint8_t)i; - break;; - } - - buffer += r; - parsed += r; - size -= r; - } - } - - /* We check to see if it's an alternate to this one */ - ifp = (struct libusb_interface_descriptor *) buffer; - if (size < LIBUSB_DT_INTERFACE_SIZE || - ifp->bDescriptorType != LIBUSB_DT_INTERFACE || - ifp->bInterfaceNumber != interface_number) - return parsed; - } - - return parsed; -err: - clear_interface(usb_interface); - return r; -} - -static void clear_configuration(struct libusb_config_descriptor *config) -{ - if (config->interface) { - int i; - for (i = 0; i < config->bNumInterfaces; i++) - clear_interface((struct libusb_interface *) - config->interface + i); - free((void *) config->interface); - } - if (config->extra) - free((void *) config->extra); -} - -static int parse_configuration(struct libusb_context *ctx, - struct libusb_config_descriptor *config, unsigned char *buffer, - int size, int host_endian) -{ - int i; - int r; - size_t tmp; - struct usb_descriptor_header header; - struct libusb_interface *usb_interface; - - 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) { - usbi_err(ctx, "too many interfaces (%d)", config->bNumInterfaces); - return LIBUSB_ERROR_IO; - } - - tmp = config->bNumInterfaces * sizeof(struct libusb_interface); - usb_interface = malloc(tmp); - config->interface = usb_interface; - if (!config->interface) - return LIBUSB_ERROR_NO_MEM; - - memset(usb_interface, 0, tmp); - buffer += config->bLength; - size -= config->bLength; - - config->extra = NULL; - config->extra_length = 0; - - for (i = 0; i < config->bNumInterfaces; i++) { - int len; - unsigned char *begin; - - /* Skip over the rest of the Class Specific or Vendor */ - /* Specific descriptors */ - begin = buffer; - while (size >= DESC_HEADER_LENGTH) { - usbi_parse_descriptor(buffer, "bb", &header, 0); - - if (header.bLength < DESC_HEADER_LENGTH) { - usbi_err(ctx, - "invalid extra config desc len (%d)", - header.bLength); - r = LIBUSB_ERROR_IO; - 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 ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || - (header.bDescriptorType == LIBUSB_DT_INTERFACE) || - (header.bDescriptorType == LIBUSB_DT_CONFIG) || - (header.bDescriptorType == LIBUSB_DT_DEVICE)) - break; - - usbi_dbg("skipping descriptor 0x%x\n", header.bDescriptorType); - buffer += header.bLength; - size -= header.bLength; - } - - /* Copy any unknown descriptors into a storage area for */ - /* drivers to later parse */ - len = (int)(buffer - begin); - if (len) { - /* FIXME: We should realloc and append here */ - if (!config->extra_length) { - config->extra = malloc(len); - if (!config->extra) { - r = LIBUSB_ERROR_NO_MEM; - goto err; - } - - memcpy((unsigned char *) config->extra, begin, len); - config->extra_length = len; - } - } - - r = parse_interface(ctx, usb_interface + i, buffer, size, host_endian); - if (r < 0) - goto err; - if (r == 0) { - config->bNumInterfaces = (uint8_t)i; - break; - } - - buffer += r; - size -= r; - } - - return size; - -err: - clear_configuration(config); - 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 r, host_endian = 0; - - r = usbi_backend->get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor, - &host_endian); - if (r < 0) - return r; - - if (!host_endian) { - dev->device_descriptor.bcdUSB = libusb_le16_to_cpu(dev->device_descriptor.bcdUSB); - dev->device_descriptor.idVendor = libusb_le16_to_cpu(dev->device_descriptor.idVendor); - dev->device_descriptor.idProduct = libusb_le16_to_cpu(dev->device_descriptor.idProduct); - dev->device_descriptor.bcdDevice = libusb_le16_to_cpu(dev->device_descriptor.bcdDevice); - } - - return LIBUSB_SUCCESS; -} - -/** \ingroup desc - * Get the USB device descriptor for a given device. - * - * This is a non-blocking function; the device descriptor is cached in memory. - * - * Note since libusbx-1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102, this - * function always succeeds. - * - * \param dev the device - * \param desc output location for the descriptor data - * \returns 0 on success or a LIBUSB_ERROR code on failure - */ -int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev, - struct libusb_device_descriptor *desc) -{ - usbi_dbg(""); - memcpy((unsigned char *) desc, (unsigned char *) &dev->device_descriptor, - sizeof (dev->device_descriptor)); - return 0; -} - -/** \ingroup desc - * Get the USB configuration descriptor for the currently active configuration. - * This is a non-blocking function which does not involve any requests being - * sent to the device. - * - * \param dev a device - * \param config output location for the USB configuration descriptor. Only - * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() - * after use. - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state - * \returns another LIBUSB_ERROR code on error - * \see libusb_get_config_descriptor - */ -int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev, - struct libusb_config_descriptor **config) -{ - struct libusb_config_descriptor _config; - unsigned char tmp[LIBUSB_DT_CONFIG_SIZE]; - unsigned char *buf = NULL; - int host_endian = 0; - int r; - - r = usbi_backend->get_active_config_descriptor(dev, tmp, - LIBUSB_DT_CONFIG_SIZE, &host_endian); - if (r < 0) - 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; - } - - usbi_parse_descriptor(tmp, "bbw", &_config, host_endian); - buf = malloc(_config.wTotalLength); - if (!buf) - return LIBUSB_ERROR_NO_MEM; - - 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); - return r; -} - -/** \ingroup desc - * Get a USB configuration descriptor based on its index. - * This is a non-blocking function which does not involve any requests being - * sent to the device. - * - * \param dev a device - * \param config_index the index of the configuration you wish to retrieve - * \param config output location for the USB configuration descriptor. Only - * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() - * after use. - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist - * \returns another LIBUSB_ERROR code on error - * \see libusb_get_active_config_descriptor() - * \see libusb_get_config_descriptor_by_value() - */ -int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev, - uint8_t config_index, struct libusb_config_descriptor **config) -{ - struct libusb_config_descriptor _config; - unsigned char tmp[LIBUSB_DT_CONFIG_SIZE]; - unsigned char *buf = NULL; - int host_endian = 0; - int r; - - usbi_dbg("index %d", config_index); - if (config_index >= dev->num_configurations) - return LIBUSB_ERROR_NOT_FOUND; - - r = usbi_backend->get_config_descriptor(dev, config_index, tmp, - LIBUSB_DT_CONFIG_SIZE, &host_endian); - if (r < 0) - 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; - } - - usbi_parse_descriptor(tmp, "bbw", &_config, host_endian); - buf = malloc(_config.wTotalLength); - if (!buf) - return LIBUSB_ERROR_NO_MEM; - - 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); - return r; -} - -/* iterate through all configurations, returning the index of the configuration - * matching a specific bConfigurationValue in the idx output parameter, or -1 - * if the config was not found. - * returns 0 or a LIBUSB_ERROR code - */ -int usbi_get_config_index_by_value(struct libusb_device *dev, - uint8_t bConfigurationValue, int *idx) -{ - uint8_t i; - - usbi_dbg("value %d", bConfigurationValue); - for (i = 0; i < dev->num_configurations; i++) { - unsigned char tmp[6]; - int host_endian; - int r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp), - &host_endian); - if (r < 0) - return r; - if (tmp[5] == bConfigurationValue) { - *idx = i; - return 0; - } - } - - *idx = -1; - return 0; -} - -/** \ingroup desc - * Get a USB configuration descriptor with a specific bConfigurationValue. - * This is a non-blocking function which does not involve any requests being - * sent to the device. - * - * \param dev a device - * \param bConfigurationValue the bConfigurationValue of the configuration you - * wish to retrieve - * \param config output location for the USB configuration descriptor. Only - * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() - * after use. - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist - * \returns another LIBUSB_ERROR code on error - * \see libusb_get_active_config_descriptor() - * \see libusb_get_config_descriptor() - */ -int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev, - uint8_t bConfigurationValue, struct libusb_config_descriptor **config) -{ - int 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) - return r; - else if (idx == -1) - return LIBUSB_ERROR_NOT_FOUND; - else - return libusb_get_config_descriptor(dev, (uint8_t) idx, config); -} - -/** \ingroup desc - * Free a configuration descriptor obtained from - * libusb_get_active_config_descriptor() or libusb_get_config_descriptor(). - * It is safe to call this function with a NULL config parameter, in which - * case the function simply returns. - * - * \param config the configuration descriptor to free - */ -void API_EXPORTED libusb_free_config_descriptor( - struct libusb_config_descriptor *config) -{ - if (!config) - return; - - clear_configuration(config); - free(config); -} - -/** \ingroup desc - * 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 - * Retrieve a string descriptor in C style ASCII. - * - * Wrapper around libusb_get_string_descriptor(). Uses the first language - * supported by the device. - * - * \param dev a device handle - * \param desc_index the index of the descriptor to retrieve - * \param data output buffer for ASCII string descriptor - * \param length size of data buffer - * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure - */ -int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev, - uint8_t desc_index, unsigned char *data, int length) -{ - unsigned char tbuf[255]; /* Some devices choke on size > 255 */ - int r, si, di; - uint16_t langid; - - /* Asking for the zero'th index is special - it returns a string - * descriptor that contains all the language IDs supported by the - * device. Typically there aren't many - often only one. Language - * IDs are 16 bit numbers, and they start at the third byte in the - * descriptor. There's also no point in trying to read descriptor 0 - * with this function. See USB 2.0 specification section 9.6.7 for - * more information. - */ - - if (desc_index == 0) - return LIBUSB_ERROR_INVALID_PARAM; - - r = libusb_get_string_descriptor(dev, 0, 0, tbuf, sizeof(tbuf)); - if (r < 0) - return r; - - if (r < 4) - return LIBUSB_ERROR_IO; - - langid = tbuf[2] | (tbuf[3] << 8); - - r = libusb_get_string_descriptor(dev, desc_index, langid, tbuf, - sizeof(tbuf)); - if (r < 0) - return r; - - if (tbuf[1] != LIBUSB_DT_STRING) - return LIBUSB_ERROR_IO; - - if (tbuf[0] > r) - return LIBUSB_ERROR_IO; - - for (di = 0, si = 2; si < tbuf[0]; si += 2) { - if (di >= (length - 1)) - break; - - if ((tbuf[si] & 0x80) || (tbuf[si + 1])) /* non-ASCII */ - data[di++] = '?'; - else - data[di++] = tbuf[si]; - } - - data[di] = 0; - return di; -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/hotplug.c b/src/3rd_party-static/libusbx-1.0.16/libusb/hotplug.c deleted file mode 100644 index 6b04342f08..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/hotplug.c +++ /dev/null @@ -1,320 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */ -/* - * 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 - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#include <assert.h> - -#include "libusbi.h" -#include "hotplug.h" - -/** - * @defgroup hotplug Device hotplug event notification - * This page details how to use the libusb hotplug interface, 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 - * - * \section intro Introduction - * - * 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 - * \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 - * expecting additional events. Returning 0 will rearm the callback and 1 will cause - * the callback to be deregistered. - * - * Callbacks for a particular context are automatically deregistered by libusb_exit(). - * - * 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_LEFT: A device has left and is no longer available - * - * A hotplug event can listen for either or both of these events. - * - * Note: If you receive notification that a device has left and you have any - * a libusb_device_handles for the device it is up to you to call libusb_close() - * on each handle to free up any remaining resources associated with the device. - * Once a device has left any libusb_device_handle associated with the device - * are invalid and will remain so even if the device comes back. - * - * When handling a LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED event it is considered - * safe to call any libusbx function that takes a libusb_device. On the other hand, - * when handling a LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT event the only safe function - * is libusb_get_device_descriptor(). - * - * The following code provides an example of the usage of the hotplug interface: -\code -static int count = 0; - -int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, - libusb_hotplug_event event, void *user_data) { - static libusb_device_handle *handle = NULL; - struct libusb_device_descriptor desc; - int rc; - - (void)libusb_get_device_descriptor(dev, &desc); - - if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == event) { - rc = libusb_open(dev, &handle); - if (LIBUSB_SUCCESS != rc) { - printf("Could not open USB device\n"); - } - } else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) { - if (handle) { - libusb_close(handle); - handle = NULL; - } - } else { - printf("Unhandled event %d\n", event); - } - count++; - - return 0; -} - -int main (void) { - libusb_hotplug_callback_handle handle; - int rc; - - libusb_init(NULL); - - rc = libusb_hotplug_register_callback(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, 0x045a, 0x5005, - LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, NULL, - &handle); - if (LIBUSB_SUCCESS != rc) { - printf("Error creating a hotplug callback\n"); - libusb_exit(NULL); - return EXIT_FAILURE; - } - - while (count < 2) { - usleep(10000); - } - - libusb_hotplug_deregister_callback(handle); - libusb_exit(NULL); - - return 0; -} -\endcode - */ - -static int usbi_hotplug_match_cb (struct libusb_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 == usbi_default_context ? NULL : ctx, - dev, event, hotplug_cb->user_data); -} - -void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, - libusb_hotplug_event event) -{ - struct libusb_hotplug_callback *hotplug_cb, *next; - int ret; - - usbi_mutex_lock(&ctx->hotplug_cbs_lock); - - list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { - usbi_mutex_unlock(&ctx->hotplug_cbs_lock); - 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); - - /* loop through and disconnect all open handles for this device */ - if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) { - struct libusb_device_handle *handle; - - usbi_mutex_lock(&ctx->open_devs_lock); - list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) { - if (dev == handle->dev) { - usbi_handle_disconnect (handle); - } - } - usbi_mutex_unlock(&ctx->open_devs_lock); - } -} - -int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, - libusb_hotplug_event events, libusb_hotplug_flag flags, - int vendor_id, int product_id, int dev_class, - libusb_hotplug_callback_fn cb_fn, void *user_data, - libusb_hotplug_callback_handle *handle) -{ - libusb_hotplug_callback *new_callback; - static int handle_id = 1; - - /* check for hotplug support */ - if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { - return LIBUSB_ERROR_NOT_SUPPORTED; - } - - /* check for sane values */ - if ((LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) || - (LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) || - (LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) || - !cb_fn) { - return LIBUSB_ERROR_INVALID_PARAM; - } - - USBI_GET_CONTEXT(ctx); - - new_callback = (libusb_hotplug_callback *)calloc(1, sizeof (*new_callback)); - if (!new_callback) { - return LIBUSB_ERROR_NO_MEM; - } - - new_callback->ctx = ctx; - new_callback->vendor_id = vendor_id; - new_callback->product_id = product_id; - new_callback->dev_class = dev_class; - new_callback->flags = flags; - new_callback->events = events; - new_callback->cb = cb_fn; - new_callback->user_data = user_data; - new_callback->needs_free = 0; - - usbi_mutex_lock(&ctx->hotplug_cbs_lock); - - /* protect the handle by the context hotplug lock. it doesn't matter if the same handle - * is used for different contexts only that the handle is unique for this context */ - new_callback->handle = handle_id++; - - list_add(&new_callback->list, &ctx->hotplug_cbs); - - if (flags & LIBUSB_HOTPLUG_ENUMERATE) { - struct libusb_device *dev; - - usbi_mutex_lock(&ctx->usb_devs_lock); - - list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) { - (void) usbi_hotplug_match_cb (ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, new_callback); - } - - usbi_mutex_unlock(&ctx->usb_devs_lock); - } - - usbi_mutex_unlock(&ctx->hotplug_cbs_lock); - - if (handle) { - *handle = new_callback->handle; - } - - return LIBUSB_SUCCESS; -} - -void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx, - libusb_hotplug_callback_handle handle) -{ - struct libusb_hotplug_callback *hotplug_cb; - 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) { - struct libusb_hotplug_callback *hotplug_cb, *next; - - usbi_mutex_lock(&ctx->hotplug_cbs_lock); - list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, - struct libusb_hotplug_callback) { - list_del(&hotplug_cb->list); - free(hotplug_cb); - } - - usbi_mutex_unlock(&ctx->hotplug_cbs_lock); -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/hotplug.h b/src/3rd_party-static/libusbx-1.0.16/libusb/hotplug.h deleted file mode 100644 index 614ddbcff0..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/hotplug.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */ -/* - * 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 - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#if !defined(USBI_HOTPLUG_H) -#define USBI_HOTPLUG_H - -#ifndef LIBUSBI_H -#include "libusbi.h" -#endif - -/** \ingroup hotplug - * The hotplug callback structure. The user populates this structure with - * libusb_hotplug_prepare_callback() and then calls libusb_hotplug_register_callback() - * to receive notification of hotplug events. - */ -struct libusb_hotplug_callback { - /** Context this callback is associated with */ - struct libusb_context *ctx; - - /** Vendor ID to match or LIBUSB_HOTPLUG_MATCH_ANY */ - int vendor_id; - - /** Product ID to match or LIBUSB_HOTPLUG_MATCH_ANY */ - int product_id; - - /** Device class to match or LIBUSB_HOTPLUG_MATCH_ANY */ - int dev_class; - - /** Hotplug callback flags */ - libusb_hotplug_flag flags; - - /** Event(s) that will trigger this callback */ - libusb_hotplug_event events; - - /** Callback function to invoke for matching event/device */ - libusb_hotplug_callback_fn cb; - - /** Handle for this callback (used to match on deregister) */ - libusb_hotplug_callback_handle handle; - - /** User data that will be passed to the callback function */ - void *user_data; - - /** Callback is marked for deletion */ - int needs_free; - - /** List this callback is registered in (ctx->hotplug_cbs) */ - struct list_head list; -}; - -typedef struct libusb_hotplug_callback libusb_hotplug_callback; - -struct libusb_hotplug_message { - libusb_hotplug_event event; - struct libusb_device *device; -}; - -typedef struct libusb_hotplug_message libusb_hotplug_message; - -void usbi_hotplug_deregister_all(struct libusb_context *ctx); -void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, - libusb_hotplug_event event); - -#endif diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/io.c b/src/3rd_party-static/libusbx-1.0.16/libusb/io.c deleted file mode 100644 index 4368b99457..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/io.c +++ /dev/null @@ -1,2566 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */ -/* - * I/O functions 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 - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include <errno.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef USBI_TIMERFD_AVAILABLE -#include <sys/timerfd.h> -#endif - -#include "libusbi.h" -#include "hotplug.h" - -/** - * \page io Synchronous and asynchronous device I/O - * - * \section intro Introduction - * - * If you're using libusbx in your application, you're probably wanting to - * perform I/O with devices - you want to perform USB data transfers. - * - * libusbx offers two separate interfaces for device I/O. This page aims to - * introduce the two in order to help you decide which one is more suitable - * for your application. You can also choose to use both interfaces in your - * application by considering each transfer on a case-by-case basis. - * - * Once you have read through the following discussion, you should consult the - * detailed API documentation pages for the details: - * - \ref syncio - * - \ref asyncio - * - * \section theory Transfers at a logical level - * - * At a logical level, USB transfers typically happen in two parts. For - * example, when reading data from a endpoint: - * -# A request for data is sent to the device - * -# Some time later, the incoming data is received by the host - * - * or when writing data to an endpoint: - * - * -# The data is sent to the device - * -# Some time later, the host receives acknowledgement from the device that - * the data has been transferred. - * - * There may be an indefinite delay between the two steps. Consider a - * fictional USB input device with a button that the user can press. In order - * to determine when the button is pressed, you would likely submit a request - * to read data on a bulk or interrupt endpoint and wait for data to arrive. - * Data will arrive when the button is pressed by the user, which is - * potentially hours later. - * - * libusbx offers both a synchronous and an asynchronous interface to performing - * USB transfers. The main difference is that the synchronous interface - * combines both steps indicated above into a single function call, whereas - * the asynchronous interface separates them. - * - * \section sync The synchronous interface - * - * The synchronous I/O interface allows you to perform a USB transfer with - * a single function call. When the function call returns, the transfer has - * completed and you can parse the results. - * - * If you have used the libusb-0.1 before, this I/O style will seem familar to - * you. libusb-0.1 only offered a synchronous interface. - * - * In our input device example, to read button presses you might write code - * in the following style: -\code -unsigned char data[4]; -int actual_length; -int r = libusb_bulk_transfer(handle, LIBUSB_ENDPOINT_IN, data, sizeof(data), &actual_length, 0); -if (r == 0 && actual_length == sizeof(data)) { - // results of the transaction can now be found in the data buffer - // parse them here and report button press -} else { - error(); -} -\endcode - * - * The main advantage of this model is simplicity: you did everything with - * a single simple function call. - * - * However, this interface has its limitations. Your application will sleep - * inside libusb_bulk_transfer() until the transaction has completed. If it - * takes the user 3 hours to press the button, your application will be - * sleeping for that long. Execution will be tied up inside the library - - * the entire thread will be useless for that duration. - * - * Another issue is that by tieing up the thread with that single transaction - * there is no possibility of performing I/O with multiple endpoints and/or - * multiple devices simultaneously, unless you resort to creating one thread - * per transaction. - * - * Additionally, there is no opportunity to cancel the transfer after the - * request has been submitted. - * - * For details on how to use the synchronous API, see the - * \ref syncio "synchronous I/O API documentation" pages. - * - * \section async The asynchronous interface - * - * Asynchronous I/O is the most significant new feature in libusb-1.0. - * Although it is a more complex interface, it solves all the issues detailed - * above. - * - * Instead of providing which functions that block until the I/O has complete, - * libusbx's asynchronous interface presents non-blocking functions which - * begin a transfer and then return immediately. Your application passes a - * callback function pointer to this non-blocking function, which libusbx will - * call with the results of the transaction when it has completed. - * - * Transfers which have been submitted through the non-blocking functions - * can be cancelled with a separate function call. - * - * The non-blocking nature of this interface allows you to be simultaneously - * performing I/O to multiple endpoints on multiple devices, without having - * to use threads. - * - * This added flexibility does come with some complications though: - * - In the interest of being a lightweight library, libusbx does not create - * threads and can only operate when your application is calling into it. Your - * application must call into libusbx from it's main loop when events are ready - * to be handled, or you must use some other scheme to allow libusbx to - * undertake whatever work needs to be done. - * - libusbx also needs to be called into at certain fixed points in time in - * order to accurately handle transfer timeouts. - * - Memory handling becomes more complex. You cannot use stack memory unless - * the function with that stack is guaranteed not to return until the transfer - * callback has finished executing. - * - You generally lose some linearity from your code flow because submitting - * the transfer request is done in a separate function from where the transfer - * results are handled. This becomes particularly obvious when you want to - * submit a second transfer based on the results of an earlier transfer. - * - * Internally, libusbx's synchronous interface is expressed in terms of function - * calls to the asynchronous interface. - * - * For details on how to use the asynchronous API, see the - * \ref asyncio "asynchronous I/O API" documentation pages. - */ - - -/** - * \page packetoverflow Packets and overflows - * - * \section packets Packet abstraction - * - * The USB specifications describe how data is transmitted in packets, with - * constraints on packet size defined by endpoint descriptors. The host must - * not send data payloads larger than the endpoint's maximum packet size. - * - * libusbx and the underlying OS abstract out the packet concept, allowing you - * to request transfers of any size. Internally, the request will be divided - * up into correctly-sized packets. You do not have to be concerned with - * packet sizes, but there is one exception when considering overflows. - * - * \section overflow Bulk/interrupt transfer overflows - * - * When requesting data on a bulk endpoint, libusbx requires you to supply a - * buffer and the maximum number of bytes of data that libusbx can put in that - * buffer. However, the size of the buffer is not communicated to the device - - * the device is just asked to send any amount of data. - * - * There is no problem if the device sends an amount of data that is less than - * or equal to the buffer size. libusbx reports this condition to you through - * the \ref libusb_transfer::actual_length "libusb_transfer.actual_length" - * field. - * - * Problems may occur if the device attempts to send more data than can fit in - * the buffer. libusbx reports LIBUSB_TRANSFER_OVERFLOW for this condition but - * other behaviour is largely undefined: actual_length may or may not be - * accurate, the chunk of data that can fit in the buffer (before overflow) - * may or may not have been transferred. - * - * Overflows are nasty, but can be avoided. Even though you were told to - * ignore packets above, think about the lower level details: each transfer is - * split into packets (typically small, with a maximum size of 512 bytes). - * Overflows can only happen if the final packet in an incoming data transfer - * is smaller than the actual packet that the device wants to transfer. - * Therefore, you will never see an overflow if your transfer buffer size is a - * multiple of the endpoint's packet size: the final packet will either - * fill up completely or will be only partially filled. - */ - -/** - * @defgroup asyncio Asynchronous device I/O - * - * This page details libusbx's asynchronous (non-blocking) API for USB device - * I/O. This interface is very powerful but is also quite complex - you will - * need to read this page carefully to understand the necessary considerations - * and issues surrounding use of this interface. Simplistic applications - * may wish to consider the \ref syncio "synchronous I/O API" instead. - * - * The asynchronous interface is built around the idea of separating transfer - * submission and handling of transfer completion (the synchronous model - * combines both of these into one). There may be a long delay between - * submission and completion, however the asynchronous submission function - * is non-blocking so will return control to your application during that - * potentially long delay. - * - * \section asyncabstraction Transfer abstraction - * - * For the asynchronous I/O, libusbx implements the concept of a generic - * transfer entity for all types of I/O (control, bulk, interrupt, - * isochronous). The generic transfer object must be treated slightly - * differently depending on which type of I/O you are performing with it. - * - * This is represented by the public libusb_transfer structure type. - * - * \section asynctrf Asynchronous transfers - * - * We can view asynchronous I/O as a 5 step process: - * -# <b>Allocation</b>: allocate a libusb_transfer - * -# <b>Filling</b>: populate the libusb_transfer instance with information - * about the transfer you wish to perform - * -# <b>Submission</b>: ask libusbx to submit the transfer - * -# <b>Completion handling</b>: examine transfer results in the - * libusb_transfer structure - * -# <b>Deallocation</b>: clean up resources - * - * - * \subsection asyncalloc Allocation - * - * This step involves allocating memory for a USB transfer. This is the - * generic transfer object mentioned above. At this stage, the transfer - * is "blank" with no details about what type of I/O it will be used for. - * - * Allocation is done with the libusb_alloc_transfer() function. You must use - * this function rather than allocating your own transfers. - * - * \subsection asyncfill Filling - * - * This step is where you take a previously allocated transfer and fill it - * with information to determine the message type and direction, data buffer, - * callback function, etc. - * - * You can either fill the required fields yourself or you can use the - * helper functions: libusb_fill_control_transfer(), libusb_fill_bulk_transfer() - * and libusb_fill_interrupt_transfer(). - * - * \subsection asyncsubmit Submission - * - * When you have allocated a transfer and filled it, you can submit it using - * libusb_submit_transfer(). This function returns immediately but can be - * regarded as firing off the I/O request in the background. - * - * \subsection asynccomplete Completion handling - * - * After a transfer has been submitted, one of four things can happen to it: - * - * - The transfer completes (i.e. some data was transferred) - * - The transfer has a timeout and the timeout expires before all data is - * transferred - * - The transfer fails due to an error - * - The transfer is cancelled - * - * Each of these will cause the user-specified transfer callback function to - * be invoked. It is up to the callback function to determine which of the - * above actually happened and to act accordingly. - * - * The user-specified callback is passed a pointer to the libusb_transfer - * structure which was used to setup and submit the transfer. At completion - * time, libusbx has populated this structure with results of the transfer: - * success or failure reason, number of bytes of data transferred, etc. See - * the libusb_transfer structure documentation for more information. - * - * \subsection Deallocation - * - * When a transfer has completed (i.e. the callback function has been invoked), - * you are advised to free the transfer (unless you wish to resubmit it, see - * below). Transfers are deallocated with libusb_free_transfer(). - * - * It is undefined behaviour to free a transfer which has not completed. - * - * \section asyncresubmit Resubmission - * - * You may be wondering why allocation, filling, and submission are all - * separated above where they could reasonably be combined into a single - * operation. - * - * The reason for separation is to allow you to resubmit transfers without - * having to allocate new ones every time. This is especially useful for - * common situations dealing with interrupt endpoints - you allocate one - * transfer, fill and submit it, and when it returns with results you just - * resubmit it for the next interrupt. - * - * \section asynccancel Cancellation - * - * Another advantage of using the asynchronous interface is that you have - * the ability to cancel transfers which have not yet completed. This is - * done by calling the libusb_cancel_transfer() function. - * - * libusb_cancel_transfer() is asynchronous/non-blocking in itself. When the - * cancellation actually completes, the transfer's callback function will - * be invoked, and the callback function should check the transfer status to - * determine that it was cancelled. - * - * Freeing the transfer after it has been cancelled but before cancellation - * has completed will result in undefined behaviour. - * - * When a transfer is cancelled, some of the data may have been transferred. - * libusbx will communicate this to you in the transfer callback. Do not assume - * that no data was transferred. - * - * \section bulk_overflows Overflows on device-to-host bulk/interrupt endpoints - * - * If your device does not have predictable transfer sizes (or it misbehaves), - * your application may submit a request for data on an IN endpoint which is - * smaller than the data that the device wishes to send. In some circumstances - * this will cause an overflow, which is a nasty condition to deal with. See - * the \ref packetoverflow page for discussion. - * - * \section asyncctrl Considerations for control transfers - * - * The <tt>libusb_transfer</tt> structure is generic and hence does not - * include specific fields for the control-specific setup packet structure. - * - * In order to perform a control transfer, you must place the 8-byte setup - * packet at the start of the data buffer. To simplify this, you could - * cast the buffer pointer to type struct libusb_control_setup, or you can - * use the helper function libusb_fill_control_setup(). - * - * The wLength field placed in the setup packet must be the length you would - * expect to be sent in the setup packet: the length of the payload that - * follows (or the expected maximum number of bytes to receive). However, - * the length field of the libusb_transfer object must be the length of - * the data buffer - i.e. it should be wLength <em>plus</em> the size of - * the setup packet (LIBUSB_CONTROL_SETUP_SIZE). - * - * If you use the helper functions, this is simplified for you: - * -# Allocate a buffer of size LIBUSB_CONTROL_SETUP_SIZE plus the size of the - * data you are sending/requesting. - * -# Call libusb_fill_control_setup() on the data buffer, using the transfer - * request size as the wLength value (i.e. do not include the extra space you - * allocated for the control setup). - * -# If this is a host-to-device transfer, place the data to be transferred - * in the data buffer, starting at offset LIBUSB_CONTROL_SETUP_SIZE. - * -# Call libusb_fill_control_transfer() to associate the data buffer with - * the transfer (and to set the remaining details such as callback and timeout). - * - Note that there is no parameter to set the length field of the transfer. - * The length is automatically inferred from the wLength field of the setup - * packet. - * -# Submit the transfer. - * - * The multi-byte control setup fields (wValue, wIndex and wLength) must - * be given in little-endian byte order (the endianness of the USB bus). - * Endianness conversion is transparently handled by - * libusb_fill_control_setup() which is documented to accept host-endian - * values. - * - * Further considerations are needed when handling transfer completion in - * your callback function: - * - As you might expect, the setup packet will still be sitting at the start - * of the data buffer. - * - If this was a device-to-host transfer, the received data will be sitting - * at offset LIBUSB_CONTROL_SETUP_SIZE into the buffer. - * - The actual_length field of the transfer structure is relative to the - * wLength of the setup packet, rather than the size of the data buffer. So, - * if your wLength was 4, your transfer's <tt>length</tt> was 12, then you - * should expect an <tt>actual_length</tt> of 4 to indicate that the data was - * transferred in entirity. - * - * To simplify parsing of setup packets and obtaining the data from the - * correct offset, you may wish to use the libusb_control_transfer_get_data() - * and libusb_control_transfer_get_setup() functions within your transfer - * callback. - * - * Even though control endpoints do not halt, a completed control transfer - * may have a LIBUSB_TRANSFER_STALL status code. This indicates the control - * request was not supported. - * - * \section asyncintr Considerations for interrupt transfers - * - * All interrupt transfers are performed using the polling interval presented - * by the bInterval value of the endpoint descriptor. - * - * \section asynciso Considerations for isochronous transfers - * - * Isochronous transfers are more complicated than transfers to - * non-isochronous endpoints. - * - * To perform I/O to an isochronous endpoint, allocate the transfer by calling - * libusb_alloc_transfer() with an appropriate number of isochronous packets. - * - * During filling, set \ref libusb_transfer::type "type" to - * \ref libusb_transfer_type::LIBUSB_TRANSFER_TYPE_ISOCHRONOUS - * "LIBUSB_TRANSFER_TYPE_ISOCHRONOUS", and set - * \ref libusb_transfer::num_iso_packets "num_iso_packets" to a value less than - * or equal to the number of packets you requested during allocation. - * libusb_alloc_transfer() does not set either of these fields for you, given - * that you might not even use the transfer on an isochronous endpoint. - * - * Next, populate the length field for the first num_iso_packets entries in - * the \ref libusb_transfer::iso_packet_desc "iso_packet_desc" array. Section - * 5.6.3 of the USB2 specifications describe how the maximum isochronous - * packet length is determined by the wMaxPacketSize field in the endpoint - * descriptor. - * Two functions can help you here: - * - * - libusb_get_max_iso_packet_size() is an easy way to determine the max - * packet size for an isochronous endpoint. Note that the maximum packet - * size is actually the maximum number of bytes that can be transmitted in - * a single microframe, therefore this function multiplies the maximum number - * of bytes per transaction by the number of transaction opportunities per - * microframe. - * - libusb_set_iso_packet_lengths() assigns the same length to all packets - * within a transfer, which is usually what you want. - * - * For outgoing transfers, you'll obviously fill the buffer and populate the - * packet descriptors in hope that all the data gets transferred. For incoming - * transfers, you must ensure the buffer has sufficient capacity for - * the situation where all packets transfer the full amount of requested data. - * - * Completion handling requires some extra consideration. The - * \ref libusb_transfer::actual_length "actual_length" field of the transfer - * is meaningless and should not be examined; instead you must refer to the - * \ref libusb_iso_packet_descriptor::actual_length "actual_length" field of - * each individual packet. - * - * The \ref libusb_transfer::status "status" field of the transfer is also a - * little misleading: - * - If the packets were submitted and the isochronous data microframes - * completed normally, status will have value - * \ref libusb_transfer_status::LIBUSB_TRANSFER_COMPLETED - * "LIBUSB_TRANSFER_COMPLETED". Note that bus errors and software-incurred - * delays are not counted as transfer errors; the transfer.status field may - * indicate COMPLETED even if some or all of the packets failed. Refer to - * the \ref libusb_iso_packet_descriptor::status "status" field of each - * individual packet to determine packet failures. - * - The status field will have value - * \ref libusb_transfer_status::LIBUSB_TRANSFER_ERROR - * "LIBUSB_TRANSFER_ERROR" only when serious errors were encountered. - * - Other transfer status codes occur with normal behaviour. - * - * The data for each packet will be found at an offset into the buffer that - * can be calculated as if each prior packet completed in full. The - * libusb_get_iso_packet_buffer() and libusb_get_iso_packet_buffer_simple() - * functions may help you here. - * - * \section asyncmem Memory caveats - * - * In most circumstances, it is not safe to use stack memory for transfer - * buffers. This is because the function that fired off the asynchronous - * transfer may return before libusbx has finished using the buffer, and when - * the function returns it's stack gets destroyed. This is true for both - * host-to-device and device-to-host transfers. - * - * The only case in which it is safe to use stack memory is where you can - * guarantee that the function owning the stack space for the buffer does not - * return until after the transfer's callback function has completed. In every - * other case, you need to use heap memory instead. - * - * \section asyncflags Fine control - * - * Through using this asynchronous interface, you may find yourself repeating - * a few simple operations many times. You can apply a bitwise OR of certain - * flags to a transfer to simplify certain things: - * - \ref libusb_transfer_flags::LIBUSB_TRANSFER_SHORT_NOT_OK - * "LIBUSB_TRANSFER_SHORT_NOT_OK" results in transfers which transferred - * less than the requested amount of data being marked with status - * \ref libusb_transfer_status::LIBUSB_TRANSFER_ERROR "LIBUSB_TRANSFER_ERROR" - * (they would normally be regarded as COMPLETED) - * - \ref libusb_transfer_flags::LIBUSB_TRANSFER_FREE_BUFFER - * "LIBUSB_TRANSFER_FREE_BUFFER" allows you to ask libusbx to free the transfer - * buffer when freeing the transfer. - * - \ref libusb_transfer_flags::LIBUSB_TRANSFER_FREE_TRANSFER - * "LIBUSB_TRANSFER_FREE_TRANSFER" causes libusbx to automatically free the - * transfer after the transfer callback returns. - * - * \section asyncevent Event handling - * - * An asynchronous model requires that libusbx perform work at various - * points in time - namely processing the results of previously-submitted - * transfers and invoking the user-supplied callback function. - * - * This gives rise to the libusb_handle_events() function which your - * application must call into when libusbx has work do to. This gives libusbx - * the opportunity to reap pending transfers, invoke callbacks, etc. - * - * There are 2 different approaches to dealing with libusb_handle_events: - * - * -# Repeatedly call libusb_handle_events() in blocking mode from a dedicated - * thread. - * -# Integrate libusbx with your application's main event loop. libusbx - * exposes a set of file descriptors which allow you to do this. - * - * The first approach has the big advantage that it will also work on Windows - * were libusbx' poll API for select / poll integration is not available. So - * if you want to support Windows and use the async API, you must use this - * approach, see the \ref eventthread "Using an event handling thread" section - * below for details. - * - * If you prefer a single threaded approach with a single central event loop, - * see the \ref poll "polling and timing" section for how to integrate libusbx - * into your application's main event loop. - * - * \section eventthread Using an event handling thread - * - * Lets begin with stating the obvious: If you're going to use a separate - * thread for libusbx event handling, your callback functions MUST be - * threadsafe. - * - * Other then that doing event handling from a separate thread, is mostly - * simple. You can use an event thread function as follows: -\code -void *event_thread_func(void *ctx) -{ - while (event_thread_run) - libusb_handle_events(ctx); - - return NULL; -} -\endcode - * - * There is one caveat though, stopping this thread requires setting the - * event_thread_run variable to 0, and after that libusb_handle_events() needs - * to return control to event_thread_func. But unless some event happens, - * libusb_handle_events() will not return. - * - * There are 2 different ways of dealing with this, depending on if your - * application uses libusbx' \ref hotplug "hotplug" support or not. - * - * Applications which do not use hotplug support, should not start the event - * thread until after their first call to libusb_open(), and should stop the - * thread when closing the last open device as follows: -\code -void my_close_handle(libusb_device_handle *handle) -{ - if (open_devs == 1) - event_thread_run = 0; - - libusb_close(handle); // This wakes up libusb_handle_events() - - if (open_devs == 1) - pthread_join(event_thread); - - open_devs--; -} -\endcode - * - * Applications using hotplug support should start the thread at program init, - * after having successfully called libusb_hotplug_register_callback(), and - * should stop the thread at program exit as follows: -\code -void my_libusb_exit(void) -{ - event_thread_run = 0; - libusb_hotplug_deregister_callback(ctx, hotplug_cb_handle); // This wakes up libusb_handle_events() - pthread_join(event_thread); - libusb_exit(ctx); -} -\endcode - */ - -/** - * @defgroup poll Polling and timing - * - * This page documents libusbx's functions for polling events and timing. - * These functions are only necessary for users of the - * \ref asyncio "asynchronous API". If you are only using the simpler - * \ref syncio "synchronous API" then you do not need to ever call these - * functions. - * - * The justification for the functionality described here has already been - * discussed in the \ref asyncevent "event handling" section of the - * asynchronous API documentation. In summary, libusbx does not create internal - * threads for event processing and hence relies on your application calling - * into libusbx at certain points in time so that pending events can be handled. - * - * Your main loop is probably already calling poll() or select() or a - * variant on a set of file descriptors for other event sources (e.g. keyboard - * button presses, mouse movements, network sockets, etc). You then add - * libusbx's file descriptors to your poll()/select() calls, and when activity - * is detected on such descriptors you know it is time to call - * libusb_handle_events(). - * - * There is one final event handling complication. libusbx supports - * asynchronous transfers which time out after a specified time period. - * - * On some platforms a timerfd is used, so the timeout handling is just another - * fd, on other platforms this requires that libusbx is called into at or after - * the timeout to handle it. So, in addition to considering libusbx's file - * descriptors in your main event loop, you must also consider that libusbx - * sometimes needs to be called into at fixed points in time even when there - * is no file descriptor activity, see \ref polltime details. - * - * In order to know precisely when libusbx needs to be called into, libusbx - * offers you a set of pollable file descriptors and information about when - * the next timeout expires. - * - * If you are using the asynchronous I/O API, you must take one of the two - * following options, otherwise your I/O will not complete. - * - * \section pollsimple The simple option - * - * If your application revolves solely around libusbx and does not need to - * handle other event sources, you can have a program structure as follows: -\code -// initialize libusbx -// find and open device -// maybe fire off some initial async I/O - -while (user_has_not_requested_exit) - libusb_handle_events(ctx); - -// clean up and exit -\endcode - * - * With such a simple main loop, you do not have to worry about managing - * sets of file descriptors or handling timeouts. libusb_handle_events() will - * handle those details internally. - * - * \section pollmain The more advanced option - * - * \note This functionality is currently only available on Unix-like platforms. - * On Windows, libusb_get_pollfds() simply returns NULL. Applications which - * want to support Windows are advised to use an \ref eventthread - * "event handling thread" instead. - * - * In more advanced applications, you will already have a main loop which - * is monitoring other event sources: network sockets, X11 events, mouse - * movements, etc. Through exposing a set of file descriptors, libusbx is - * designed to cleanly integrate into such main loops. - * - * In addition to polling file descriptors for the other event sources, you - * take a set of file descriptors from libusbx and monitor those too. When you - * detect activity on libusbx's file descriptors, you call - * libusb_handle_events_timeout() in non-blocking mode. - * - * What's more, libusbx may also need to handle events at specific moments in - * time. No file descriptor activity is generated at these times, so your - * own application needs to be continually aware of when the next one of these - * moments occurs (through calling libusb_get_next_timeout()), and then it - * needs to call libusb_handle_events_timeout() in non-blocking mode when - * these moments occur. This means that you need to adjust your - * poll()/select() timeout accordingly. - * - * libusbx provides you with a set of file descriptors to poll and expects you - * to poll all of them, treating them as a single entity. The meaning of each - * file descriptor in the set is an internal implementation detail, - * platform-dependent and may vary from release to release. Don't try and - * interpret the meaning of the file descriptors, just do as libusbx indicates, - * polling all of them at once. - * - * In pseudo-code, you want something that looks like: -\code -// initialise libusbx - -libusb_get_pollfds(ctx) -while (user has not requested application exit) { - libusb_get_next_timeout(ctx); - poll(on libusbx file descriptors plus any other event sources of interest, - using a timeout no larger than the value libusbx just suggested) - if (poll() indicated activity on libusbx file descriptors) - libusb_handle_events_timeout(ctx, &zero_tv); - if (time has elapsed to or beyond the libusbx timeout) - libusb_handle_events_timeout(ctx, &zero_tv); - // handle events from other sources here -} - -// clean up and exit -\endcode - * - * \subsection polltime Notes on time-based events - * - * The above complication with having to track time and call into libusbx at - * specific moments is a bit of a headache. For maximum compatibility, you do - * need to write your main loop as above, but you may decide that you can - * restrict the supported platforms of your application and get away with - * a more simplistic scheme. - * - * These time-based event complications are \b not required on the following - * platforms: - * - Darwin - * - Linux, provided that the following version requirements are satisfied: - * - Linux v2.6.27 or newer, compiled with timerfd support - * - glibc v2.9 or newer - * - libusbx v1.0.5 or newer - * - * Under these configurations, libusb_get_next_timeout() will \em always return - * 0, so your main loop can be simplified to: -\code -// initialise libusbx - -libusb_get_pollfds(ctx) -while (user has not requested application exit) { - poll(on libusbx file descriptors plus any other event sources of interest, - using any timeout that you like) - if (poll() indicated activity on libusbx file descriptors) - libusb_handle_events_timeout(ctx, &zero_tv); - // handle events from other sources here -} - -// clean up and exit -\endcode - * - * Do remember that if you simplify your main loop to the above, you will - * lose compatibility with some platforms (including legacy Linux platforms, - * and <em>any future platforms supported by libusbx which may have time-based - * event requirements</em>). The resultant problems will likely appear as - * strange bugs in your application. - * - * You can use the libusb_pollfds_handle_timeouts() function to do a runtime - * check to see if it is safe to ignore the time-based event complications. - * If your application has taken the shortcut of ignoring libusbx's next timeout - * in your main loop, then you are advised to check the return value of - * libusb_pollfds_handle_timeouts() during application startup, and to abort - * if the platform does suffer from these timing complications. - * - * \subsection fdsetchange Changes in the file descriptor set - * - * The set of file descriptors that libusbx uses as event sources may change - * during the life of your application. Rather than having to repeatedly - * call libusb_get_pollfds(), you can set up notification functions for when - * the file descriptor set changes using libusb_set_pollfd_notifiers(). - * - * \subsection mtissues Multi-threaded considerations - * - * Unfortunately, the situation is complicated further when multiple threads - * come into play. If two threads are monitoring the same file descriptors, - * the fact that only one thread will be woken up when an event occurs causes - * some headaches. - * - * The events lock, event waiters lock, and libusb_handle_events_locked() - * entities are added to solve these problems. You do not need to be concerned - * with these entities otherwise. - * - * See the extra documentation: \ref mtasync - */ - -/** \page mtasync Multi-threaded applications and asynchronous I/O - * - * libusbx is a thread-safe library, but extra considerations must be applied - * to applications which interact with libusbx from multiple threads. - * - * The underlying issue that must be addressed is that all libusbx I/O - * revolves around monitoring file descriptors through the poll()/select() - * system calls. This is directly exposed at the - * \ref asyncio "asynchronous interface" but it is important to note that the - * \ref syncio "synchronous interface" is implemented on top of the - * asynchonrous interface, therefore the same considerations apply. - * - * The issue is that if two or more threads are concurrently calling poll() - * or select() on libusbx's file descriptors then only one of those threads - * will be woken up when an event arrives. The others will be completely - * oblivious that anything has happened. - * - * Consider the following pseudo-code, which submits an asynchronous transfer - * then waits for its completion. This style is one way you could implement a - * synchronous interface on top of the asynchronous interface (and libusbx - * does something similar, albeit more advanced due to the complications - * explained on this page). - * -\code -void cb(struct libusb_transfer *transfer) -{ - int *completed = transfer->user_data; - *completed = 1; -} - -void myfunc() { - struct libusb_transfer *transfer; - unsigned char buffer[LIBUSB_CONTROL_SETUP_SIZE]; - int completed = 0; - - transfer = libusb_alloc_transfer(0); - libusb_fill_control_setup(buffer, - LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, 0x04, 0x01, 0, 0); - libusb_fill_control_transfer(transfer, dev, buffer, cb, &completed, 1000); - libusb_submit_transfer(transfer); - - while (!completed) { - poll(libusbx file descriptors, 120*1000); - if (poll indicates activity) - libusb_handle_events_timeout(ctx, &zero_tv); - } - printf("completed!"); - // other code here -} -\endcode - * - * Here we are <em>serializing</em> completion of an asynchronous event - * against a condition - the condition being completion of a specific transfer. - * The poll() loop has a long timeout to minimize CPU usage during situations - * when nothing is happening (it could reasonably be unlimited). - * - * If this is the only thread that is polling libusbx's file descriptors, there - * is no problem: there is no danger that another thread will swallow up the - * event that we are interested in. On the other hand, if there is another - * thread polling the same descriptors, there is a chance that it will receive - * the event that we were interested in. In this situation, <tt>myfunc()</tt> - * will only realise that the transfer has completed on the next iteration of - * the loop, <em>up to 120 seconds later.</em> Clearly a two-minute delay is - * undesirable, and don't even think about using short timeouts to circumvent - * this issue! - * - * The solution here is to ensure that no two threads are ever polling the - * file descriptors at the same time. A naive implementation of this would - * impact the capabilities of the library, so libusbx offers the scheme - * documented below to ensure no loss of functionality. - * - * Before we go any further, it is worth mentioning that all libusb-wrapped - * event handling procedures fully adhere to the scheme documented below. - * This includes libusb_handle_events() and its variants, and all the - * synchronous I/O functions - libusbx hides this headache from you. - * - * \section Using libusb_handle_events() from multiple threads - * - * Even when only using libusb_handle_events() and synchronous I/O functions, - * you can still have a race condition. You might be tempted to solve the - * above with libusb_handle_events() like so: - * -\code - libusb_submit_transfer(transfer); - - while (!completed) { - libusb_handle_events(ctx); - } - printf("completed!"); -\endcode - * - * This however has a race between the checking of completed and - * libusb_handle_events() acquiring the events lock, so another thread - * could have completed the transfer, resulting in this thread hanging - * until either a timeout or another event occurs. See also commit - * 6696512aade99bb15d6792af90ae329af270eba6 which fixes this in the - * synchronous API implementation of libusb. - * - * Fixing this race requires checking the variable completed only after - * taking the event lock, which defeats the concept of just calling - * libusb_handle_events() without worrying about locking. This is why - * libusb-1.0.9 introduces the new libusb_handle_events_timeout_completed() - * and libusb_handle_events_completed() functions, which handles doing the - * completion check for you after they have acquired the lock: - * -\code - libusb_submit_transfer(transfer); - - while (!completed) { - libusb_handle_events_completed(ctx, &completed); - } - printf("completed!"); -\endcode - * - * This nicely fixes the race in our example. Note that if all you want to - * do is submit a single transfer and wait for its completion, then using - * one of the synchronous I/O functions is much easier. - * - * \section eventlock The events lock - * - * The problem is when we consider the fact that libusbx exposes file - * descriptors to allow for you to integrate asynchronous USB I/O into - * existing main loops, effectively allowing you to do some work behind - * libusbx's back. If you do take libusbx's file descriptors and pass them to - * poll()/select() yourself, you need to be aware of the associated issues. - * - * The first concept to be introduced is the events lock. The events lock - * is used to serialize threads that want to handle events, such that only - * one thread is handling events at any one time. - * - * You must take the events lock before polling libusbx file descriptors, - * using libusb_lock_events(). You must release the lock as soon as you have - * aborted your poll()/select() loop, using libusb_unlock_events(). - * - * \section threadwait Letting other threads do the work for you - * - * Although the events lock is a critical part of the solution, it is not - * enough on it's own. You might wonder if the following is sufficient... -\code - libusb_lock_events(ctx); - while (!completed) { - poll(libusbx file descriptors, 120*1000); - if (poll indicates activity) - libusb_handle_events_timeout(ctx, &zero_tv); - } - libusb_unlock_events(ctx); -\endcode - * ...and the answer is that it is not. This is because the transfer in the - * code shown above may take a long time (say 30 seconds) to complete, and - * the lock is not released until the transfer is completed. - * - * Another thread with similar code that wants to do event handling may be - * working with a transfer that completes after a few milliseconds. Despite - * having such a quick completion time, the other thread cannot check that - * status of its transfer until the code above has finished (30 seconds later) - * due to contention on the lock. - * - * To solve this, libusbx offers you a mechanism to determine when another - * thread is handling events. It also offers a mechanism to block your thread - * until the event handling thread has completed an event (and this mechanism - * does not involve polling of file descriptors). - * - * After determining that another thread is currently handling events, you - * obtain the <em>event waiters</em> lock using libusb_lock_event_waiters(). - * You then re-check that some other thread is still handling events, and if - * so, you call libusb_wait_for_event(). - * - * libusb_wait_for_event() puts your application to sleep until an event - * occurs, or until a thread releases the events lock. When either of these - * things happen, your thread is woken up, and should re-check the condition - * it was waiting on. It should also re-check that another thread is handling - * events, and if not, it should start handling events itself. - * - * This looks like the following, as pseudo-code: -\code -retry: -if (libusb_try_lock_events(ctx) == 0) { - // we obtained the event lock: do our own event handling - while (!completed) { - if (!libusb_event_handling_ok(ctx)) { - libusb_unlock_events(ctx); - goto retry; - } - poll(libusbx file descriptors, 120*1000); - if (poll indicates activity) - libusb_handle_events_locked(ctx, 0); - } - libusb_unlock_events(ctx); -} else { - // another thread is doing event handling. wait for it to signal us that - // an event has completed - libusb_lock_event_waiters(ctx); - - while (!completed) { - // now that we have the event waiters lock, double check that another - // thread is still handling events for us. (it may have ceased handling - // events in the time it took us to reach this point) - if (!libusb_event_handler_active(ctx)) { - // whoever was handling events is no longer doing so, try again - libusb_unlock_event_waiters(ctx); - goto retry; - } - - libusb_wait_for_event(ctx, NULL); - } - libusb_unlock_event_waiters(ctx); -} -printf("completed!\n"); -\endcode - * - * A naive look at the above code may suggest that this can only support - * one event waiter (hence a total of 2 competing threads, the other doing - * event handling), because the event waiter seems to have taken the event - * waiters lock while waiting for an event. However, the system does support - * multiple event waiters, because libusb_wait_for_event() actually drops - * the lock while waiting, and reaquires it before continuing. - * - * We have now implemented code which can dynamically handle situations where - * nobody is handling events (so we should do it ourselves), and it can also - * handle situations where another thread is doing event handling (so we can - * piggyback onto them). It is also equipped to handle a combination of - * the two, for example, another thread is doing event handling, but for - * whatever reason it stops doing so before our condition is met, so we take - * over the event handling. - * - * Four functions were introduced in the above pseudo-code. Their importance - * should be apparent from the code shown above. - * -# libusb_try_lock_events() is a non-blocking function which attempts - * to acquire the events lock but returns a failure code if it is contended. - * -# libusb_event_handling_ok() checks that libusbx is still happy for your - * thread to be performing event handling. Sometimes, libusbx needs to - * interrupt the event handler, and this is how you can check if you have - * been interrupted. If this function returns 0, the correct behaviour is - * for you to give up the event handling lock, and then to repeat the cycle. - * The following libusb_try_lock_events() will fail, so you will become an - * events waiter. For more information on this, read \ref fullstory below. - * -# libusb_handle_events_locked() is a variant of - * libusb_handle_events_timeout() that you can call while holding the - * events lock. libusb_handle_events_timeout() itself implements similar - * logic to the above, so be sure not to call it when you are - * "working behind libusbx's back", as is the case here. - * -# libusb_event_handler_active() determines if someone is currently - * holding the events lock - * - * You might be wondering why there is no function to wake up all threads - * blocked on libusb_wait_for_event(). This is because libusbx can do this - * internally: it will wake up all such threads when someone calls - * libusb_unlock_events() or when a transfer completes (at the point after its - * callback has returned). - * - * \subsection fullstory The full story - * - * The above explanation should be enough to get you going, but if you're - * really thinking through the issues then you may be left with some more - * questions regarding libusbx's internals. If you're curious, read on, and if - * not, skip to the next section to avoid confusing yourself! - * - * The immediate question that may spring to mind is: what if one thread - * modifies the set of file descriptors that need to be polled while another - * thread is doing event handling? - * - * There are 2 situations in which this may happen. - * -# libusb_open() will add another file descriptor to the poll set, - * therefore it is desirable to interrupt the event handler so that it - * restarts, picking up the new descriptor. - * -# libusb_close() will remove a file descriptor from the poll set. There - * are all kinds of race conditions that could arise here, so it is - * important that nobody is doing event handling at this time. - * - * libusbx handles these issues internally, so application developers do not - * have to stop their event handlers while opening/closing devices. Here's how - * it works, focusing on the libusb_close() situation first: - * - * -# During initialization, libusbx opens an internal pipe, and it adds the read - * end of this pipe to the set of file descriptors to be polled. - * -# During libusb_close(), libusbx writes some dummy data on this control pipe. - * This immediately interrupts the event handler. libusbx also records - * internally that it is trying to interrupt event handlers for this - * high-priority event. - * -# At this point, some of the functions described above start behaving - * differently: - * - libusb_event_handling_ok() starts returning 1, indicating that it is NOT - * OK for event handling to continue. - * - libusb_try_lock_events() starts returning 1, indicating that another - * thread holds the event handling lock, even if the lock is uncontended. - * - libusb_event_handler_active() starts returning 1, indicating that - * another thread is doing event handling, even if that is not true. - * -# The above changes in behaviour result in the event handler stopping and - * giving up the events lock very quickly, giving the high-priority - * libusb_close() operation a "free ride" to acquire the events lock. All - * threads that are competing to do event handling become event waiters. - * -# With the events lock held inside libusb_close(), libusbx can safely remove - * a file descriptor from the poll set, in the safety of knowledge that - * nobody is polling those descriptors or trying to access the poll set. - * -# After obtaining the events lock, the close operation completes very - * quickly (usually a matter of milliseconds) and then immediately releases - * the events lock. - * -# At the same time, the behaviour of libusb_event_handling_ok() and friends - * reverts to the original, documented behaviour. - * -# The release of the events lock causes the threads that are waiting for - * events to be woken up and to start competing to become event handlers - * again. One of them will succeed; it will then re-obtain the list of poll - * descriptors, and USB I/O will then continue as normal. - * - * libusb_open() is similar, and is actually a more simplistic case. Upon a - * call to libusb_open(): - * - * -# The device is opened and a file descriptor is added to the poll set. - * -# libusbx sends some dummy data on the control pipe, and records that it - * is trying to modify the poll descriptor set. - * -# The event handler is interrupted, and the same behaviour change as for - * libusb_close() takes effect, causing all event handling threads to become - * event waiters. - * -# The libusb_open() implementation takes its free ride to the events lock. - * -# Happy that it has successfully paused the events handler, libusb_open() - * releases the events lock. - * -# The event waiter threads are all woken up and compete to become event - * handlers again. The one that succeeds will obtain the list of poll - * descriptors again, which will include the addition of the new device. - * - * \subsection concl Closing remarks - * - * The above may seem a little complicated, but hopefully I have made it clear - * why such complications are necessary. Also, do not forget that this only - * applies to applications that take libusbx's file descriptors and integrate - * them into their own polling loops. - * - * You may decide that it is OK for your multi-threaded application to ignore - * some of the rules and locks detailed above, because you don't think that - * two threads can ever be polling the descriptors at the same time. If that - * is the case, then that's good news for you because you don't have to worry. - * But be careful here; remember that the synchronous I/O functions do event - * handling internally. If you have one thread doing event handling in a loop - * (without implementing the rules and locking semantics documented above) - * and another trying to send a synchronous USB transfer, you will end up with - * two threads monitoring the same descriptors, and the above-described - * undesirable behaviour occuring. The solution is for your polling thread to - * play by the rules; the synchronous I/O functions do so, and this will result - * in them getting along in perfect harmony. - * - * If you do have a dedicated thread doing event handling, it is perfectly - * legal for it to take the event handling lock for long periods of time. Any - * synchronous I/O functions you call from other threads will transparently - * fall back to the "event waiters" mechanism detailed above. The only - * consideration that your event handling thread must apply is the one related - * to libusb_event_handling_ok(): you must call this before every poll(), and - * give up the events lock if instructed. - */ - -int usbi_io_init(struct libusb_context *ctx) -{ - int r; - - usbi_mutex_init(&ctx->flying_transfers_lock, NULL); - usbi_mutex_init(&ctx->pollfds_lock, NULL); - usbi_mutex_init(&ctx->pollfd_modify_lock, NULL); - usbi_mutex_init_recursive(&ctx->events_lock, NULL); - usbi_mutex_init(&ctx->event_waiters_lock, NULL); - usbi_cond_init(&ctx->event_waiters_cond, NULL); - list_init(&ctx->flying_transfers); - list_init(&ctx->pollfds); - - /* FIXME should use an eventfd on kernels that support it */ - r = usbi_pipe(ctx->ctrl_pipe); - if (r < 0) { - r = LIBUSB_ERROR_OTHER; - goto err; - } - - r = usbi_add_pollfd(ctx, ctx->ctrl_pipe[0], POLLIN); - if (r < 0) - goto err_close_pipe; - - /* create hotplug pipe */ - r = usbi_pipe(ctx->hotplug_pipe); - if (r < 0) { - r = LIBUSB_ERROR_OTHER; - goto err; - } - - r = usbi_add_pollfd(ctx, ctx->hotplug_pipe[0], POLLIN); - if (r < 0) - goto err_close_hp_pipe; - -#ifdef USBI_TIMERFD_AVAILABLE - ctx->timerfd = timerfd_create(usbi_backend->get_timerfd_clockid(), - TFD_NONBLOCK); - if (ctx->timerfd >= 0) { - usbi_dbg("using timerfd for timeouts"); - r = usbi_add_pollfd(ctx, ctx->timerfd, POLLIN); - if (r < 0) { - usbi_remove_pollfd(ctx, ctx->ctrl_pipe[0]); - close(ctx->timerfd); - goto err_close_hp_pipe; - } - } else { - usbi_dbg("timerfd not available (code %d error %d)", ctx->timerfd, errno); - ctx->timerfd = -1; - } -#endif - - return 0; - -err_close_hp_pipe: - usbi_close(ctx->hotplug_pipe[0]); - usbi_close(ctx->hotplug_pipe[1]); -err_close_pipe: - usbi_close(ctx->ctrl_pipe[0]); - usbi_close(ctx->ctrl_pipe[1]); -err: - usbi_mutex_destroy(&ctx->flying_transfers_lock); - usbi_mutex_destroy(&ctx->pollfds_lock); - usbi_mutex_destroy(&ctx->pollfd_modify_lock); - usbi_mutex_destroy(&ctx->events_lock); - usbi_mutex_destroy(&ctx->event_waiters_lock); - usbi_cond_destroy(&ctx->event_waiters_cond); - return r; -} - -void usbi_io_exit(struct libusb_context *ctx) -{ - usbi_remove_pollfd(ctx, ctx->ctrl_pipe[0]); - usbi_close(ctx->ctrl_pipe[0]); - usbi_close(ctx->ctrl_pipe[1]); - usbi_remove_pollfd(ctx, ctx->hotplug_pipe[0]); - usbi_close(ctx->hotplug_pipe[0]); - usbi_close(ctx->hotplug_pipe[1]); -#ifdef USBI_TIMERFD_AVAILABLE - if (usbi_using_timerfd(ctx)) { - usbi_remove_pollfd(ctx, ctx->timerfd); - close(ctx->timerfd); - } -#endif - usbi_mutex_destroy(&ctx->flying_transfers_lock); - usbi_mutex_destroy(&ctx->pollfds_lock); - usbi_mutex_destroy(&ctx->pollfd_modify_lock); - usbi_mutex_destroy(&ctx->events_lock); - usbi_mutex_destroy(&ctx->event_waiters_lock); - usbi_cond_destroy(&ctx->event_waiters_cond); -} - -static int calculate_timeout(struct usbi_transfer *transfer) -{ - int r; - struct timespec current_time; - unsigned int timeout = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout; - - if (!timeout) - return 0; - - r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, ¤t_time); - if (r < 0) { - usbi_err(ITRANSFER_CTX(transfer), - "failed to read monotonic clock, errno=%d", errno); - return r; - } - - current_time.tv_sec += timeout / 1000; - current_time.tv_nsec += (timeout % 1000) * 1000000; - - while (current_time.tv_nsec >= 1000000000) { - current_time.tv_nsec -= 1000000000; - current_time.tv_sec++; - } - - TIMESPEC_TO_TIMEVAL(&transfer->timeout, ¤t_time); - return 0; -} - -/* add a transfer to the (timeout-sorted) active transfers list. - * Callers of this function must hold the flying_transfers_lock. - * This function *always* adds the transfer to the flying_transfers list, - * it will return non 0 if it fails to update the timer, but even then the - * transfer is added to the flying_transfers list. */ -static int add_to_flying_list(struct usbi_transfer *transfer) -{ - struct usbi_transfer *cur; - struct timeval *timeout = &transfer->timeout; - struct libusb_context *ctx = ITRANSFER_CTX(transfer); - int r = 0; - int first = 1; - - /* if we have no other flying transfers, start the list with this one */ - if (list_empty(&ctx->flying_transfers)) { - list_add(&transfer->list, &ctx->flying_transfers); - goto out; - } - - /* if we have infinite timeout, append to end of list */ - if (!timerisset(timeout)) { - list_add_tail(&transfer->list, &ctx->flying_transfers); - /* first is irrelevant in this case */ - goto out; - } - - /* otherwise, find appropriate place in list */ - list_for_each_entry(cur, &ctx->flying_transfers, list, struct usbi_transfer) { - /* find first timeout that occurs after the transfer in question */ - struct timeval *cur_tv = &cur->timeout; - - if (!timerisset(cur_tv) || (cur_tv->tv_sec > timeout->tv_sec) || - (cur_tv->tv_sec == timeout->tv_sec && - cur_tv->tv_usec > timeout->tv_usec)) { - list_add_tail(&transfer->list, &cur->list); - goto out; - } - first = 0; - } - /* first is 0 at this stage (list not empty) */ - - /* otherwise we need to be inserted at the end */ - list_add_tail(&transfer->list, &ctx->flying_transfers); -out: -#ifdef USBI_TIMERFD_AVAILABLE - if (first && usbi_using_timerfd(ctx) && timerisset(timeout)) { - /* if this transfer has the lowest timeout of all active transfers, - * rearm the timerfd with this transfer's timeout */ - const struct itimerspec it = { {0, 0}, - { timeout->tv_sec, timeout->tv_usec * 1000 } }; - usbi_dbg("arm timerfd for timeout in %dms (first in line)", - USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout); - r = timerfd_settime(ctx->timerfd, TFD_TIMER_ABSTIME, &it, NULL); - if (r < 0) { - usbi_warn(ctx, "failed to arm first timerfd (errno %d)", errno); - r = LIBUSB_ERROR_OTHER; - } - } -#else - UNUSED(first); -#endif - - return r; -} - -/** \ingroup asyncio - * Allocate a libusbx transfer with a specified number of isochronous packet - * descriptors. The returned transfer is pre-initialized for you. When the new - * transfer is no longer needed, it should be freed with - * libusb_free_transfer(). - * - * Transfers intended for non-isochronous endpoints (e.g. control, bulk, - * interrupt) should specify an iso_packets count of zero. - * - * For transfers intended for isochronous endpoints, specify an appropriate - * number of packet descriptors to be allocated as part of the transfer. - * The returned transfer is not specially initialized for isochronous I/O; - * you are still required to set the - * \ref libusb_transfer::num_iso_packets "num_iso_packets" and - * \ref libusb_transfer::type "type" fields accordingly. - * - * It is safe to allocate a transfer with some isochronous packets and then - * use it on a non-isochronous endpoint. If you do this, ensure that at time - * of submission, num_iso_packets is 0 and that type is set appropriately. - * - * \param iso_packets number of isochronous packet descriptors to allocate - * \returns a newly allocated transfer, or NULL on error - */ -DEFAULT_VISIBILITY -struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer( - int iso_packets) -{ - size_t os_alloc_size = usbi_backend->transfer_priv_size - + (usbi_backend->add_iso_packet_size * iso_packets); - size_t alloc_size = sizeof(struct usbi_transfer) - + sizeof(struct libusb_transfer) - + (sizeof(struct libusb_iso_packet_descriptor) * iso_packets) - + os_alloc_size; - struct usbi_transfer *itransfer = calloc(1, alloc_size); - if (!itransfer) - return NULL; - - itransfer->num_iso_packets = iso_packets; - usbi_mutex_init(&itransfer->lock, NULL); - return USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); -} - -/** \ingroup asyncio - * Free a transfer structure. This should be called for all transfers - * allocated with libusb_alloc_transfer(). - * - * If the \ref libusb_transfer_flags::LIBUSB_TRANSFER_FREE_BUFFER - * "LIBUSB_TRANSFER_FREE_BUFFER" flag is set and the transfer buffer is - * non-NULL, this function will also free the transfer buffer using the - * standard system memory allocator (e.g. free()). - * - * It is legal to call this function with a NULL transfer. In this case, - * the function will simply return safely. - * - * It is not legal to free an active transfer (one which has been submitted - * and has not yet completed). - * - * \param transfer the transfer to free - */ -void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer) -{ - struct usbi_transfer *itransfer; - if (!transfer) - return; - - if (transfer->flags & LIBUSB_TRANSFER_FREE_BUFFER && transfer->buffer) - free(transfer->buffer); - - itransfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); - usbi_mutex_destroy(&itransfer->lock); - free(itransfer); -} - -#ifdef USBI_TIMERFD_AVAILABLE -static int disarm_timerfd(struct libusb_context *ctx) -{ - const struct itimerspec disarm_timer = { { 0, 0 }, { 0, 0 } }; - int r; - - usbi_dbg(""); - r = timerfd_settime(ctx->timerfd, 0, &disarm_timer, NULL); - if (r < 0) - return LIBUSB_ERROR_OTHER; - else - return 0; -} - -/* iterates through the flying transfers, and rearms the timerfd based on the - * next upcoming timeout. - * must be called with flying_list locked. - * returns 0 if there was no timeout to arm, 1 if the next timeout was armed, - * or a LIBUSB_ERROR code on failure. - */ -static int arm_timerfd_for_next_timeout(struct libusb_context *ctx) -{ - struct usbi_transfer *transfer; - - list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { - struct timeval *cur_tv = &transfer->timeout; - - /* if we've reached transfers of infinite timeout, then we have no - * arming to do */ - if (!timerisset(cur_tv)) - goto disarm; - - /* act on first transfer that is not already cancelled */ - if (!(transfer->flags & USBI_TRANSFER_TIMED_OUT)) { - int r; - const struct itimerspec it = { {0, 0}, - { cur_tv->tv_sec, cur_tv->tv_usec * 1000 } }; - usbi_dbg("next timeout originally %dms", USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout); - r = timerfd_settime(ctx->timerfd, TFD_TIMER_ABSTIME, &it, NULL); - if (r < 0) - return LIBUSB_ERROR_OTHER; - return 1; - } - } - -disarm: - return disarm_timerfd(ctx); -} -#else -static int arm_timerfd_for_next_timeout(struct libusb_context *ctx) -{ - (void)ctx; - return 0; -} -#endif - -/** \ingroup asyncio - * Submit a transfer. This function will fire off the USB transfer and then - * return immediately. - * - * \param transfer the transfer to submit - * \returns 0 on success - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_BUSY if the transfer has already been submitted. - * \returns LIBUSB_ERROR_NOT_SUPPORTED if the transfer flags are not supported - * by the operating system. - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer) -{ - struct libusb_context *ctx = TRANSFER_CTX(transfer); - struct usbi_transfer *itransfer = - LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); - int r; - int updated_fds; - - usbi_mutex_lock(&itransfer->lock); - itransfer->transferred = 0; - itransfer->flags = 0; - r = calculate_timeout(itransfer); - if (r < 0) { - r = LIBUSB_ERROR_OTHER; - goto out; - } - - usbi_mutex_lock(&ctx->flying_transfers_lock); - r = add_to_flying_list(itransfer); - if (r == LIBUSB_SUCCESS) { - r = usbi_backend->submit_transfer(itransfer); - } - if (r != LIBUSB_SUCCESS) { - list_del(&itransfer->list); - arm_timerfd_for_next_timeout(ctx); - } - usbi_mutex_unlock(&ctx->flying_transfers_lock); - -out: - updated_fds = (itransfer->flags & USBI_TRANSFER_UPDATED_FDS); - usbi_mutex_unlock(&itransfer->lock); - if (updated_fds) - usbi_fd_notification(ctx); - return r; -} - -/** \ingroup asyncio - * Asynchronously cancel a previously submitted transfer. - * This function returns immediately, but this does not indicate cancellation - * is complete. Your callback function will be invoked at some later time - * with a transfer status of - * \ref libusb_transfer_status::LIBUSB_TRANSFER_CANCELLED - * "LIBUSB_TRANSFER_CANCELLED." - * - * \param transfer the transfer to cancel - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the transfer is already complete or - * cancelled. - * \returns a LIBUSB_ERROR code on failure - */ -int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer) -{ - struct usbi_transfer *itransfer = - LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); - int r; - - usbi_dbg(""); - usbi_mutex_lock(&itransfer->lock); - r = usbi_backend->cancel_transfer(itransfer); - if (r < 0) { - if (r != LIBUSB_ERROR_NOT_FOUND && - r != LIBUSB_ERROR_NO_DEVICE) - usbi_err(TRANSFER_CTX(transfer), - "cancel transfer failed error %d", r); - else - usbi_dbg("cancel transfer failed error %d", r); - - if (r == LIBUSB_ERROR_NO_DEVICE) - itransfer->flags |= USBI_TRANSFER_DEVICE_DISAPPEARED; - } - - itransfer->flags |= USBI_TRANSFER_CANCELLING; - - usbi_mutex_unlock(&itransfer->lock); - return r; -} - -/* Handle completion of a transfer (completion might be an error condition). - * This will invoke the user-supplied callback function, which may end up - * freeing the transfer. Therefore you cannot use the transfer structure - * after calling this function, and you should free all backend-specific - * data before calling it. - * Do not call this function with the usbi_transfer lock held. User-specified - * callback functions may attempt to directly resubmit the transfer, which - * will attempt to take the lock. */ -int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, - enum libusb_transfer_status status) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = TRANSFER_CTX(transfer); - uint8_t flags; - int r = 0; - - /* FIXME: could be more intelligent with the timerfd here. we don't need - * to disarm the timerfd if there was no timer running, and we only need - * to rearm the timerfd if the transfer that expired was the one with - * the shortest timeout. */ - - usbi_mutex_lock(&ctx->flying_transfers_lock); - list_del(&itransfer->list); - if (usbi_using_timerfd(ctx)) - r = arm_timerfd_for_next_timeout(ctx); - usbi_mutex_unlock(&ctx->flying_transfers_lock); - if (usbi_using_timerfd(ctx) && (r < 0)) - return r; - - if (status == LIBUSB_TRANSFER_COMPLETED - && transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { - int rqlen = transfer->length; - if (transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL) - rqlen -= LIBUSB_CONTROL_SETUP_SIZE; - if (rqlen != itransfer->transferred) { - usbi_dbg("interpreting short transfer as error"); - status = LIBUSB_TRANSFER_ERROR; - } - } - - flags = transfer->flags; - transfer->status = status; - transfer->actual_length = itransfer->transferred; - usbi_dbg("transfer %p has callback %p", transfer, transfer->callback); - if (transfer->callback) - transfer->callback(transfer); - /* transfer might have been freed by the above call, do not use from - * this point. */ - if (flags & LIBUSB_TRANSFER_FREE_TRANSFER) - libusb_free_transfer(transfer); - usbi_mutex_lock(&ctx->event_waiters_lock); - usbi_cond_broadcast(&ctx->event_waiters_cond); - usbi_mutex_unlock(&ctx->event_waiters_lock); - return 0; -} - -/* Similar to usbi_handle_transfer_completion() but exclusively for transfers - * that were asynchronously cancelled. The same concerns w.r.t. freeing of - * transfers exist here. - * Do not call this function with the usbi_transfer lock held. User-specified - * callback functions may attempt to directly resubmit the transfer, which - * will attempt to take the lock. */ -int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer) -{ - /* if the URB was cancelled due to timeout, report timeout to the user */ - if (transfer->flags & USBI_TRANSFER_TIMED_OUT) { - usbi_dbg("detected timeout cancellation"); - return usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_TIMED_OUT); - } - - /* otherwise its a normal async cancel */ - return usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_CANCELLED); -} - -/** \ingroup poll - * Attempt to acquire the event handling lock. This lock is used to ensure that - * only one thread is monitoring libusbx event sources at any one time. - * - * You only need to use this lock if you are developing an application - * which calls poll() or select() on libusbx's file descriptors directly. - * If you stick to libusbx's event handling loop functions (e.g. - * libusb_handle_events()) then you do not need to be concerned with this - * locking. - * - * While holding this lock, you are trusted to actually be handling events. - * If you are no longer handling events, you must call libusb_unlock_events() - * as soon as possible. - * - * \param ctx the context to operate on, or NULL for the default context - * \returns 0 if the lock was obtained successfully - * \returns 1 if the lock was not obtained (i.e. another thread holds the lock) - * \see \ref mtasync - */ -int API_EXPORTED libusb_try_lock_events(libusb_context *ctx) -{ - int r; - unsigned int ru; - USBI_GET_CONTEXT(ctx); - - /* is someone else waiting to modify poll fds? if so, don't let this thread - * start event handling */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ru = ctx->pollfd_modify; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - if (ru) { - usbi_dbg("someone else is modifying poll fds"); - return 1; - } - - r = usbi_mutex_trylock(&ctx->events_lock); - if (r) - return 1; - - ctx->event_handler_active = 1; - return 0; -} - -/** \ingroup poll - * Acquire the event handling lock, blocking until successful acquisition if - * it is contended. This lock is used to ensure that only one thread is - * monitoring libusbx event sources at any one time. - * - * You only need to use this lock if you are developing an application - * which calls poll() or select() on libusbx's file descriptors directly. - * If you stick to libusbx's event handling loop functions (e.g. - * libusb_handle_events()) then you do not need to be concerned with this - * locking. - * - * While holding this lock, you are trusted to actually be handling events. - * If you are no longer handling events, you must call libusb_unlock_events() - * as soon as possible. - * - * \param ctx the context to operate on, or NULL for the default context - * \see \ref mtasync - */ -void API_EXPORTED libusb_lock_events(libusb_context *ctx) -{ - USBI_GET_CONTEXT(ctx); - usbi_mutex_lock(&ctx->events_lock); - ctx->event_handler_active = 1; -} - -/** \ingroup poll - * Release the lock previously acquired with libusb_try_lock_events() or - * libusb_lock_events(). Releasing this lock will wake up any threads blocked - * on libusb_wait_for_event(). - * - * \param ctx the context to operate on, or NULL for the default context - * \see \ref mtasync - */ -void API_EXPORTED libusb_unlock_events(libusb_context *ctx) -{ - USBI_GET_CONTEXT(ctx); - ctx->event_handler_active = 0; - usbi_mutex_unlock(&ctx->events_lock); - - /* FIXME: perhaps we should be a bit more efficient by not broadcasting - * the availability of the events lock when we are modifying pollfds - * (check ctx->pollfd_modify)? */ - usbi_mutex_lock(&ctx->event_waiters_lock); - usbi_cond_broadcast(&ctx->event_waiters_cond); - usbi_mutex_unlock(&ctx->event_waiters_lock); -} - -/** \ingroup poll - * Determine if it is still OK for this thread to be doing event handling. - * - * Sometimes, libusbx needs to temporarily pause all event handlers, and this - * is the function you should use before polling file descriptors to see if - * this is the case. - * - * If this function instructs your thread to give up the events lock, you - * should just continue the usual logic that is documented in \ref mtasync. - * On the next iteration, your thread will fail to obtain the events lock, - * and will hence become an event waiter. - * - * This function should be called while the events lock is held: you don't - * need to worry about the results of this function if your thread is not - * the current event handler. - * - * \param ctx the context to operate on, or NULL for the default context - * \returns 1 if event handling can start or continue - * \returns 0 if this thread must give up the events lock - * \see \ref fullstory "Multi-threaded I/O: the full story" - */ -int API_EXPORTED libusb_event_handling_ok(libusb_context *ctx) -{ - unsigned int r; - USBI_GET_CONTEXT(ctx); - - /* is someone else waiting to modify poll fds? if so, don't let this thread - * continue event handling */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - r = ctx->pollfd_modify; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - if (r) { - usbi_dbg("someone else is modifying poll fds"); - return 0; - } - - return 1; -} - - -/** \ingroup poll - * Determine if an active thread is handling events (i.e. if anyone is holding - * the event handling lock). - * - * \param ctx the context to operate on, or NULL for the default context - * \returns 1 if a thread is handling events - * \returns 0 if there are no threads currently handling events - * \see \ref mtasync - */ -int API_EXPORTED libusb_event_handler_active(libusb_context *ctx) -{ - unsigned int r; - USBI_GET_CONTEXT(ctx); - - /* is someone else waiting to modify poll fds? if so, don't let this thread - * start event handling -- indicate that event handling is happening */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - r = ctx->pollfd_modify; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - if (r) { - usbi_dbg("someone else is modifying poll fds"); - return 1; - } - - return ctx->event_handler_active; -} - -/** \ingroup poll - * Acquire the event waiters lock. This lock is designed to be obtained under - * the situation where you want to be aware when events are completed, but - * some other thread is event handling so calling libusb_handle_events() is not - * allowed. - * - * You then obtain this lock, re-check that another thread is still handling - * events, then call libusb_wait_for_event(). - * - * You only need to use this lock if you are developing an application - * which calls poll() or select() on libusbx's file descriptors directly, - * <b>and</b> may potentially be handling events from 2 threads simultaenously. - * If you stick to libusbx's event handling loop functions (e.g. - * libusb_handle_events()) then you do not need to be concerned with this - * locking. - * - * \param ctx the context to operate on, or NULL for the default context - * \see \ref mtasync - */ -void API_EXPORTED libusb_lock_event_waiters(libusb_context *ctx) -{ - USBI_GET_CONTEXT(ctx); - usbi_mutex_lock(&ctx->event_waiters_lock); -} - -/** \ingroup poll - * Release the event waiters lock. - * \param ctx the context to operate on, or NULL for the default context - * \see \ref mtasync - */ -void API_EXPORTED libusb_unlock_event_waiters(libusb_context *ctx) -{ - USBI_GET_CONTEXT(ctx); - usbi_mutex_unlock(&ctx->event_waiters_lock); -} - -/** \ingroup poll - * Wait for another thread to signal completion of an event. Must be called - * with the event waiters lock held, see libusb_lock_event_waiters(). - * - * This function will block until any of the following conditions are met: - * -# The timeout expires - * -# A transfer completes - * -# A thread releases the event handling lock through libusb_unlock_events() - * - * Condition 1 is obvious. Condition 2 unblocks your thread <em>after</em> - * the callback for the transfer has completed. Condition 3 is important - * because it means that the thread that was previously handling events is no - * longer doing so, so if any events are to complete, another thread needs to - * step up and start event handling. - * - * This function releases the event waiters lock before putting your thread - * to sleep, and reacquires the lock as it is being woken up. - * - * \param ctx the context to operate on, or NULL for the default context - * \param tv maximum timeout for this blocking function. A NULL value - * indicates unlimited timeout. - * \returns 0 after a transfer completes or another thread stops event handling - * \returns 1 if the timeout expired - * \see \ref mtasync - */ -int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv) -{ - struct timespec timeout; - int r; - - USBI_GET_CONTEXT(ctx); - if (tv == NULL) { - usbi_cond_wait(&ctx->event_waiters_cond, &ctx->event_waiters_lock); - return 0; - } - - r = usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &timeout); - if (r < 0) { - usbi_err(ctx, "failed to read realtime clock, error %d", errno); - return LIBUSB_ERROR_OTHER; - } - - timeout.tv_sec += tv->tv_sec; - timeout.tv_nsec += tv->tv_usec * 1000; - while (timeout.tv_nsec >= 1000000000) { - timeout.tv_nsec -= 1000000000; - timeout.tv_sec++; - } - - r = usbi_cond_timedwait(&ctx->event_waiters_cond, - &ctx->event_waiters_lock, &timeout); - return (r == ETIMEDOUT); -} - -static void handle_timeout(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - int r; - - itransfer->flags |= USBI_TRANSFER_TIMED_OUT; - r = libusb_cancel_transfer(transfer); - if (r < 0) - usbi_warn(TRANSFER_CTX(transfer), - "async cancel failed %d errno=%d", r, errno); -} - -static int handle_timeouts_locked(struct libusb_context *ctx) -{ - int r; - struct timespec systime_ts; - struct timeval systime; - struct usbi_transfer *transfer; - - if (list_empty(&ctx->flying_transfers)) - return 0; - - /* get current time */ - r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &systime_ts); - if (r < 0) - return r; - - TIMESPEC_TO_TIMEVAL(&systime, &systime_ts); - - /* iterate through flying transfers list, finding all transfers that - * have expired timeouts */ - list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { - struct timeval *cur_tv = &transfer->timeout; - - /* if we've reached transfers of infinite timeout, we're all done */ - if (!timerisset(cur_tv)) - return 0; - - /* ignore timeouts we've already handled */ - if (transfer->flags & (USBI_TRANSFER_TIMED_OUT | USBI_TRANSFER_OS_HANDLES_TIMEOUT)) - continue; - - /* if transfer has non-expired timeout, nothing more to do */ - if ((cur_tv->tv_sec > systime.tv_sec) || - (cur_tv->tv_sec == systime.tv_sec && - cur_tv->tv_usec > systime.tv_usec)) - return 0; - - /* otherwise, we've got an expired timeout to handle */ - handle_timeout(transfer); - } - return 0; -} - -static int handle_timeouts(struct libusb_context *ctx) -{ - int r; - USBI_GET_CONTEXT(ctx); - usbi_mutex_lock(&ctx->flying_transfers_lock); - r = handle_timeouts_locked(ctx); - usbi_mutex_unlock(&ctx->flying_transfers_lock); - return r; -} - -#ifdef USBI_TIMERFD_AVAILABLE -static int handle_timerfd_trigger(struct libusb_context *ctx) -{ - int r; - - usbi_mutex_lock(&ctx->flying_transfers_lock); - - /* process the timeout that just happened */ - r = handle_timeouts_locked(ctx); - if (r < 0) - goto out; - - /* arm for next timeout*/ - r = arm_timerfd_for_next_timeout(ctx); - -out: - usbi_mutex_unlock(&ctx->flying_transfers_lock); - return r; -} -#endif - -/* do the actual event handling. assumes that no other thread is concurrently - * doing the same thing. */ -static int handle_events(struct libusb_context *ctx, struct timeval *tv) -{ - int r; - struct usbi_pollfd *ipollfd; - POLL_NFDS_TYPE nfds = 0; - struct pollfd *fds = NULL; - int i = -1; - int timeout_ms; - - usbi_mutex_lock(&ctx->pollfds_lock); - list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) - nfds++; - - /* TODO: malloc when number of fd's changes, not on every poll */ - if (nfds != 0) - fds = malloc(sizeof(*fds) * nfds); - if (!fds) { - usbi_mutex_unlock(&ctx->pollfds_lock); - return LIBUSB_ERROR_NO_MEM; - } - - list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) { - struct libusb_pollfd *pollfd = &ipollfd->pollfd; - int fd = pollfd->fd; - i++; - fds[i].fd = fd; - fds[i].events = pollfd->events; - fds[i].revents = 0; - } - usbi_mutex_unlock(&ctx->pollfds_lock); - - timeout_ms = (int)(tv->tv_sec * 1000) + (tv->tv_usec / 1000); - - /* round up to next millisecond */ - if (tv->tv_usec % 1000) - timeout_ms++; - - usbi_dbg("poll() %d fds with timeout in %dms", nfds, timeout_ms); - r = usbi_poll(fds, nfds, timeout_ms); - usbi_dbg("poll() returned %d", r); - if (r == 0) { - free(fds); - return handle_timeouts(ctx); - } else if (r == -1 && errno == EINTR) { - free(fds); - return LIBUSB_ERROR_INTERRUPTED; - } else if (r < 0) { - free(fds); - usbi_err(ctx, "poll failed %d err=%d\n", r, errno); - return LIBUSB_ERROR_IO; - } - - /* fd[0] is always the ctrl pipe */ - if (fds[0].revents) { - /* another thread wanted to interrupt event handling, and it succeeded! - * handle any other events that cropped up at the same time, and - * simply return */ - usbi_dbg("caught a fish on the control pipe"); - - if (r == 1) { - r = 0; - goto handled; - } else { - /* prevent OS backend from trying to handle events on ctrl pipe */ - fds[0].revents = 0; - r--; - } - } - - /* fd[1] is always the hotplug pipe */ - if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) && fds[1].revents) { - libusb_hotplug_message message; - ssize_t ret; - - usbi_dbg("caught a fish on the hotplug pipe"); - - /* read the message from the hotplug thread */ - ret = usbi_read(ctx->hotplug_pipe[0], &message, sizeof (message)); - if (ret < sizeof(message)) { - usbi_err(ctx, "hotplug pipe read error %d < %d", - ret, sizeof(message)); - r = LIBUSB_ERROR_OTHER; - goto handled; - } - - usbi_hotplug_match(ctx, message.device, message.event); - - /* the device left. dereference the device */ - if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == message.event) - libusb_unref_device(message.device); - - fds[1].revents = 0; - if (1 == r--) - goto handled; - } /* else there shouldn't be anything on this pipe */ - -#ifdef USBI_TIMERFD_AVAILABLE - /* on timerfd configurations, fds[2] is the timerfd */ - if (usbi_using_timerfd(ctx) && fds[2].revents) { - /* timerfd indicates that a timeout has expired */ - int ret; - usbi_dbg("timerfd triggered"); - - ret = handle_timerfd_trigger(ctx); - if (ret < 0) { - /* return error code */ - r = ret; - goto handled; - } else if (r == 1) { - /* no more active file descriptors, nothing more to do */ - r = 0; - goto handled; - } else { - /* more events pending... - * prevent OS backend from trying to handle events on timerfd */ - fds[2].revents = 0; - r--; - } - } -#endif - - r = usbi_backend->handle_events(ctx, fds, nfds, r); - if (r) - usbi_err(ctx, "backend handle_events failed with error %d", r); - -handled: - free(fds); - return r; -} - -/* returns the smallest of: - * 1. timeout of next URB - * 2. user-supplied timeout - * returns 1 if there is an already-expired timeout, otherwise returns 0 - * and populates out - */ -static int get_next_timeout(libusb_context *ctx, struct timeval *tv, - struct timeval *out) -{ - struct timeval timeout; - int r = libusb_get_next_timeout(ctx, &timeout); - if (r) { - /* timeout already expired? */ - if (!timerisset(&timeout)) - return 1; - - /* choose the smallest of next URB timeout or user specified timeout */ - if (timercmp(&timeout, tv, <)) - *out = timeout; - else - *out = *tv; - } else { - *out = *tv; - } - return 0; -} - -/** \ingroup poll - * Handle any pending events. - * - * libusbx determines "pending events" by checking if any timeouts have expired - * and by checking the set of file descriptors for activity. - * - * If a zero timeval is passed, this function will handle any already-pending - * events and then immediately return in non-blocking style. - * - * If a non-zero timeval is passed and no events are currently pending, this - * function will block waiting for events to handle up until the specified - * timeout. If an event arrives or a signal is raised, this function will - * return early. - * - * If the parameter completed is not NULL then <em>after obtaining the event - * handling lock</em> this function will return immediately if the integer - * pointed to is not 0. This allows for race free waiting for the completion - * of a specific transfer. - * - * \param ctx the context to operate on, or NULL for the default context - * \param tv the maximum time to block waiting for events, or an all zero - * timeval struct for non-blocking mode - * \param completed pointer to completion integer to check, or NULL - * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \see \ref mtasync - */ -int API_EXPORTED libusb_handle_events_timeout_completed(libusb_context *ctx, - struct timeval *tv, int *completed) -{ - int r; - struct timeval poll_timeout; - - USBI_GET_CONTEXT(ctx); - r = get_next_timeout(ctx, tv, &poll_timeout); - if (r) { - /* timeout already expired */ - return handle_timeouts(ctx); - } - -retry: - if (libusb_try_lock_events(ctx) == 0) { - if (completed == NULL || !*completed) { - /* we obtained the event lock: do our own event handling */ - usbi_dbg("doing our own event handling"); - r = handle_events(ctx, &poll_timeout); - } - libusb_unlock_events(ctx); - return r; - } - - /* another thread is doing event handling. wait for thread events that - * notify event completion. */ - libusb_lock_event_waiters(ctx); - - if (completed && *completed) - goto already_done; - - if (!libusb_event_handler_active(ctx)) { - /* we hit a race: whoever was event handling earlier finished in the - * time it took us to reach this point. try the cycle again. */ - libusb_unlock_event_waiters(ctx); - usbi_dbg("event handler was active but went away, retrying"); - goto retry; - } - - usbi_dbg("another thread is doing event handling"); - r = libusb_wait_for_event(ctx, &poll_timeout); - -already_done: - libusb_unlock_event_waiters(ctx); - - if (r < 0) - return r; - else if (r == 1) - return handle_timeouts(ctx); - else - return 0; -} - -/** \ingroup poll - * Handle any pending events - * - * Like libusb_handle_events_timeout_completed(), but without the completed - * parameter, calling this function is equivalent to calling - * libusb_handle_events_timeout_completed() with a NULL completed parameter. - * - * This function is kept primarily for backwards compatibility. - * All new code should call libusb_handle_events_completed() or - * libusb_handle_events_timeout_completed() to avoid race conditions. - * - * \param ctx the context to operate on, or NULL for the default context - * \param tv the maximum time to block waiting for events, or an all zero - * timeval struct for non-blocking mode - * \returns 0 on success, or a LIBUSB_ERROR code on failure - */ -int API_EXPORTED libusb_handle_events_timeout(libusb_context *ctx, - struct timeval *tv) -{ - return libusb_handle_events_timeout_completed(ctx, tv, NULL); -} - -/** \ingroup poll - * Handle any pending events in blocking mode. There is currently a timeout - * hardcoded at 60 seconds but we plan to make it unlimited in future. For - * finer control over whether this function is blocking or non-blocking, or - * for control over the timeout, use libusb_handle_events_timeout_completed() - * instead. - * - * This function is kept primarily for backwards compatibility. - * All new code should call libusb_handle_events_completed() or - * libusb_handle_events_timeout_completed() to avoid race conditions. - * - * \param ctx the context to operate on, or NULL for the default context - * \returns 0 on success, or a LIBUSB_ERROR code on failure - */ -int API_EXPORTED libusb_handle_events(libusb_context *ctx) -{ - struct timeval tv; - tv.tv_sec = 60; - tv.tv_usec = 0; - return libusb_handle_events_timeout_completed(ctx, &tv, NULL); -} - -/** \ingroup poll - * Handle any pending events in blocking mode. - * - * Like libusb_handle_events(), with the addition of a completed parameter - * to allow for race free waiting for the completion of a specific transfer. - * - * See libusb_handle_events_timeout_completed() for details on the completed - * parameter. - * - * \param ctx the context to operate on, or NULL for the default context - * \param completed pointer to completion integer to check, or NULL - * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \see \ref mtasync - */ -int API_EXPORTED libusb_handle_events_completed(libusb_context *ctx, - int *completed) -{ - struct timeval tv; - tv.tv_sec = 60; - tv.tv_usec = 0; - return libusb_handle_events_timeout_completed(ctx, &tv, completed); -} - -/** \ingroup poll - * Handle any pending events by polling file descriptors, without checking if - * any other threads are already doing so. Must be called with the event lock - * held, see libusb_lock_events(). - * - * This function is designed to be called under the situation where you have - * taken the event lock and are calling poll()/select() directly on libusbx's - * file descriptors (as opposed to using libusb_handle_events() or similar). - * You detect events on libusbx's descriptors, so you then call this function - * with a zero timeout value (while still holding the event lock). - * - * \param ctx the context to operate on, or NULL for the default context - * \param tv the maximum time to block waiting for events, or zero for - * non-blocking mode - * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \see \ref mtasync - */ -int API_EXPORTED libusb_handle_events_locked(libusb_context *ctx, - struct timeval *tv) -{ - int r; - struct timeval poll_timeout; - - USBI_GET_CONTEXT(ctx); - r = get_next_timeout(ctx, tv, &poll_timeout); - if (r) { - /* timeout already expired */ - return handle_timeouts(ctx); - } - - return handle_events(ctx, &poll_timeout); -} - -/** \ingroup poll - * Determines whether your application must apply special timing considerations - * when monitoring libusbx's file descriptors. - * - * This function is only useful for applications which retrieve and poll - * libusbx's file descriptors in their own main loop (\ref pollmain). - * - * Ordinarily, libusbx's event handler needs to be called into at specific - * moments in time (in addition to times when there is activity on the file - * descriptor set). The usual approach is to use libusb_get_next_timeout() - * to learn about when the next timeout occurs, and to adjust your - * poll()/select() timeout accordingly so that you can make a call into the - * library at that time. - * - * Some platforms supported by libusbx do not come with this baggage - any - * events relevant to timing will be represented by activity on the file - * descriptor set, and libusb_get_next_timeout() will always return 0. - * This function allows you to detect whether you are running on such a - * platform. - * - * Since v1.0.5. - * - * \param ctx the context to operate on, or NULL for the default context - * \returns 0 if you must call into libusbx at times determined by - * libusb_get_next_timeout(), or 1 if all timeout events are handled internally - * or through regular activity on the file descriptors. - * \see \ref pollmain "Polling libusbx file descriptors for event handling" - */ -int API_EXPORTED libusb_pollfds_handle_timeouts(libusb_context *ctx) -{ -#if defined(USBI_TIMERFD_AVAILABLE) - USBI_GET_CONTEXT(ctx); - return usbi_using_timerfd(ctx); -#else - (void)ctx; - return 0; -#endif -} - -/** \ingroup poll - * Determine the next internal timeout that libusbx needs to handle. You only - * need to use this function if you are calling poll() or select() or similar - * on libusbx's file descriptors yourself - you do not need to use it if you - * are calling libusb_handle_events() or a variant directly. - * - * You should call this function in your main loop in order to determine how - * long to wait for select() or poll() to return results. libusbx needs to be - * called into at this timeout, so you should use it as an upper bound on - * your select() or poll() call. - * - * When the timeout has expired, call into libusb_handle_events_timeout() - * (perhaps in non-blocking mode) so that libusbx can handle the timeout. - * - * This function may return 1 (success) and an all-zero timeval. If this is - * the case, it indicates that libusbx has a timeout that has already expired - * so you should call libusb_handle_events_timeout() or similar immediately. - * A return code of 0 indicates that there are no pending timeouts. - * - * On some platforms, this function will always returns 0 (no pending - * timeouts). See \ref polltime. - * - * \param ctx the context to operate on, or NULL for the default context - * \param tv output location for a relative time against the current - * clock in which libusbx must be called into in order to process timeout events - * \returns 0 if there are no pending timeouts, 1 if a timeout was returned, - * or LIBUSB_ERROR_OTHER on failure - */ -int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx, - struct timeval *tv) -{ - struct usbi_transfer *transfer; - struct timespec cur_ts; - struct timeval cur_tv; - struct timeval *next_timeout; - int r; - int found = 0; - - USBI_GET_CONTEXT(ctx); - if (usbi_using_timerfd(ctx)) - return 0; - - usbi_mutex_lock(&ctx->flying_transfers_lock); - if (list_empty(&ctx->flying_transfers)) { - usbi_mutex_unlock(&ctx->flying_transfers_lock); - usbi_dbg("no URBs, no timeout!"); - return 0; - } - - /* find next transfer which hasn't already been processed as timed out */ - list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { - if (transfer->flags & (USBI_TRANSFER_TIMED_OUT | USBI_TRANSFER_OS_HANDLES_TIMEOUT)) - continue; - - /* no timeout for this transfer? */ - if (!timerisset(&transfer->timeout)) - continue; - - found = 1; - break; - } - usbi_mutex_unlock(&ctx->flying_transfers_lock); - - if (!found) { - usbi_dbg("no URB with timeout or all handled by OS; no timeout!"); - return 0; - } - - next_timeout = &transfer->timeout; - - r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &cur_ts); - if (r < 0) { - usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno); - return 0; - } - TIMESPEC_TO_TIMEVAL(&cur_tv, &cur_ts); - - if (!timercmp(&cur_tv, next_timeout, <)) { - usbi_dbg("first timeout already expired"); - timerclear(tv); - } else { - timersub(next_timeout, &cur_tv, tv); - usbi_dbg("next timeout in %d.%06ds", tv->tv_sec, tv->tv_usec); - } - - return 1; -} - -/** \ingroup poll - * Register notification functions for file descriptor additions/removals. - * These functions will be invoked for every new or removed file descriptor - * that libusbx uses as an event source. - * - * To remove notifiers, pass NULL values for the function pointers. - * - * Note that file descriptors may have been added even before you register - * these notifiers (e.g. at libusb_init() time). - * - * Additionally, note that the removal notifier may be called during - * libusb_exit() (e.g. when it is closing file descriptors that were opened - * and added to the poll set at libusb_init() time). If you don't want this, - * remove the notifiers immediately before calling libusb_exit(). - * - * \param ctx the context to operate on, or NULL for the default context - * \param added_cb pointer to function for addition notifications - * \param removed_cb pointer to function for removal notifications - * \param user_data User data to be passed back to callbacks (useful for - * passing context information) - */ -void API_EXPORTED libusb_set_pollfd_notifiers(libusb_context *ctx, - libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, - void *user_data) -{ - USBI_GET_CONTEXT(ctx); - ctx->fd_added_cb = added_cb; - ctx->fd_removed_cb = removed_cb; - ctx->fd_cb_user_data = user_data; -} - -/* Add a file descriptor to the list of file descriptors to be monitored. - * events should be specified as a bitmask of events passed to poll(), e.g. - * POLLIN and/or POLLOUT. */ -int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events) -{ - struct usbi_pollfd *ipollfd = malloc(sizeof(*ipollfd)); - if (!ipollfd) - return LIBUSB_ERROR_NO_MEM; - - usbi_dbg("add fd %d events %d", fd, events); - ipollfd->pollfd.fd = fd; - ipollfd->pollfd.events = events; - usbi_mutex_lock(&ctx->pollfds_lock); - list_add_tail(&ipollfd->list, &ctx->pollfds); - usbi_mutex_unlock(&ctx->pollfds_lock); - - if (ctx->fd_added_cb) - ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data); - return 0; -} - -/* Remove a file descriptor from the list of file descriptors to be polled. */ -void usbi_remove_pollfd(struct libusb_context *ctx, int fd) -{ - struct usbi_pollfd *ipollfd; - int found = 0; - - usbi_dbg("remove fd %d", fd); - usbi_mutex_lock(&ctx->pollfds_lock); - list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) - if (ipollfd->pollfd.fd == fd) { - found = 1; - break; - } - - if (!found) { - usbi_dbg("couldn't find fd %d to remove", fd); - usbi_mutex_unlock(&ctx->pollfds_lock); - return; - } - - list_del(&ipollfd->list); - usbi_mutex_unlock(&ctx->pollfds_lock); - free(ipollfd); - if (ctx->fd_removed_cb) - ctx->fd_removed_cb(fd, ctx->fd_cb_user_data); -} - -/** \ingroup poll - * Retrieve a list of file descriptors that should be polled by your main loop - * as libusbx event sources. - * - * The returned list is NULL-terminated and should be freed with free() when - * done. The actual list contents must not be touched. - * - * As file descriptors are a Unix-specific concept, this function is not - * available on Windows and will always return NULL. - * - * \param ctx the context to operate on, or NULL for the default context - * \returns a NULL-terminated list of libusb_pollfd structures - * \returns NULL on error - * \returns NULL on platforms where the functionality is not available - */ -DEFAULT_VISIBILITY -const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds( - libusb_context *ctx) -{ -#ifndef OS_WINDOWS - struct libusb_pollfd **ret = NULL; - struct usbi_pollfd *ipollfd; - size_t i = 0; - size_t cnt = 0; - USBI_GET_CONTEXT(ctx); - - usbi_mutex_lock(&ctx->pollfds_lock); - list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) - cnt++; - - ret = calloc(cnt + 1, sizeof(struct libusb_pollfd *)); - if (!ret) - goto out; - - list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) - ret[i++] = (struct libusb_pollfd *) ipollfd; - ret[cnt] = NULL; - -out: - usbi_mutex_unlock(&ctx->pollfds_lock); - return (const struct libusb_pollfd **) ret; -#else - usbi_err(ctx, "external polling of libusbx's internal descriptors "\ - "is not yet supported on Windows platforms"); - return NULL; -#endif -} - -/* Backends may call this from handle_events to report disconnection of a - * device. This function ensures transfers get cancelled appropriately. - * Callers of this function must hold the events_lock. - */ -void usbi_handle_disconnect(struct libusb_device_handle *handle) -{ - struct usbi_transfer *cur; - struct usbi_transfer *to_cancel; - - usbi_dbg("device %d.%d", - handle->dev->bus_number, handle->dev->device_address); - - /* terminate all pending transfers with the LIBUSB_TRANSFER_NO_DEVICE - * status code. - * - * this is a bit tricky because: - * 1. we can't do transfer completion while holding flying_transfers_lock - * because the completion handler may try to re-submit the transfer - * 2. the transfers list can change underneath us - if we were to build a - * list of transfers to complete (while holding lock), the situation - * might be different by the time we come to free them - * - * so we resort to a loop-based approach as below - * - * This is safe because transfers are only removed from the - * flying_transfer list by usbi_handle_transfer_completion and - * libusb_close, both of which hold the events_lock while doing so, - * so usbi_handle_disconnect cannot be running at the same time. - * - * Note that libusb_submit_transfer also removes the transfer from - * the flying_transfer list on submission failure, but it keeps the - * flying_transfer list locked between addition and removal, so - * usbi_handle_disconnect never sees such transfers. - */ - - while (1) { - usbi_mutex_lock(&HANDLE_CTX(handle)->flying_transfers_lock); - to_cancel = NULL; - list_for_each_entry(cur, &HANDLE_CTX(handle)->flying_transfers, list, struct usbi_transfer) - if (USBI_TRANSFER_TO_LIBUSB_TRANSFER(cur)->dev_handle == handle) { - to_cancel = cur; - break; - } - usbi_mutex_unlock(&HANDLE_CTX(handle)->flying_transfers_lock); - - if (!to_cancel) - break; - - usbi_dbg("cancelling transfer %p from disconnect", - USBI_TRANSFER_TO_LIBUSB_TRANSFER(to_cancel)); - - usbi_backend->clear_transfer_priv(to_cancel); - usbi_handle_transfer_completion(to_cancel, LIBUSB_TRANSFER_NO_DEVICE); - } - -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/libusb-1.0.def b/src/3rd_party-static/libusbx-1.0.16/libusb/libusb-1.0.def deleted file mode 100644 index cb0e32ab93..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/libusb-1.0.def +++ /dev/null @@ -1,158 +0,0 @@ -LIBRARY "libusb-1.0.dll" -EXPORTS - libusb_alloc_transfer - libusb_alloc_transfer@4 = libusb_alloc_transfer - libusb_attach_kernel_driver - libusb_attach_kernel_driver@8 = libusb_attach_kernel_driver - libusb_bulk_transfer - libusb_bulk_transfer@24 = libusb_bulk_transfer - libusb_cancel_transfer - libusb_cancel_transfer@4 = libusb_cancel_transfer - libusb_claim_interface - libusb_claim_interface@8 = libusb_claim_interface - libusb_clear_halt - libusb_clear_halt@8 = libusb_clear_halt - libusb_close - libusb_close@4 = libusb_close - libusb_control_transfer - libusb_control_transfer@32 = libusb_control_transfer - libusb_detach_kernel_driver - libusb_detach_kernel_driver@8 = libusb_detach_kernel_driver - libusb_error_name - libusb_error_name@4 = libusb_error_name - libusb_event_handler_active - libusb_event_handler_active@4 = libusb_event_handler_active - libusb_event_handling_ok - libusb_event_handling_ok@4 = libusb_event_handling_ok - libusb_exit - libusb_exit@4 = libusb_exit - libusb_free_bos_descriptor - libusb_free_bos_descriptor@4 = libusb_free_bos_descriptor - 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@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@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@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@4 = libusb_get_bus_number - libusb_get_config_descriptor - libusb_get_config_descriptor@12 = libusb_get_config_descriptor - libusb_get_config_descriptor_by_value - libusb_get_config_descriptor_by_value@12 = libusb_get_config_descriptor_by_value - libusb_get_configuration - libusb_get_configuration@8 = libusb_get_configuration - libusb_get_container_id_descriptor - libusb_get_container_id_descriptor@12 = libusb_get_container_id_descriptor - libusb_get_device - libusb_get_device@4 = libusb_get_device - libusb_get_device_address - libusb_get_device_address@4 = libusb_get_device_address - libusb_get_device_descriptor - libusb_get_device_descriptor@8 = libusb_get_device_descriptor - libusb_get_device_list - libusb_get_device_list@8 = libusb_get_device_list - libusb_get_device_speed - libusb_get_device_speed@4 = libusb_get_device_speed - libusb_get_max_iso_packet_size - libusb_get_max_iso_packet_size@8 = libusb_get_max_iso_packet_size - libusb_get_max_packet_size - libusb_get_max_packet_size@8 = libusb_get_max_packet_size - libusb_get_next_timeout - libusb_get_next_timeout@8 = libusb_get_next_timeout - libusb_get_parent - libusb_get_parent@4 = libusb_get_parent - 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@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@0 = libusb_get_version - libusb_handle_events - libusb_handle_events@4 = libusb_handle_events - libusb_handle_events_completed - libusb_handle_events_completed@8 = libusb_handle_events_completed - libusb_handle_events_locked - libusb_handle_events_locked@8 = libusb_handle_events_locked - libusb_handle_events_timeout - libusb_handle_events_timeout@8 = libusb_handle_events_timeout - libusb_handle_events_timeout_completed - libusb_handle_events_timeout_completed@12 = libusb_handle_events_timeout_completed - libusb_has_capability - libusb_has_capability@4 = libusb_has_capability - libusb_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@4 = libusb_init - libusb_interrupt_transfer - libusb_interrupt_transfer@24 = libusb_interrupt_transfer - libusb_kernel_driver_active - libusb_kernel_driver_active@8 = libusb_kernel_driver_active - libusb_lock_event_waiters - libusb_lock_event_waiters@4 = libusb_lock_event_waiters - libusb_lock_events - libusb_lock_events@4 = libusb_lock_events - libusb_open - libusb_open@8 = libusb_open - libusb_open_device_with_vid_pid - libusb_open_device_with_vid_pid@12 = libusb_open_device_with_vid_pid - libusb_pollfds_handle_timeouts - libusb_pollfds_handle_timeouts@4 = libusb_pollfds_handle_timeouts - libusb_ref_device - libusb_ref_device@4 = libusb_ref_device - libusb_release_interface - libusb_release_interface@8 = libusb_release_interface - libusb_reset_device - libusb_reset_device@4 = libusb_reset_device - libusb_set_auto_detach_kernel_driver - libusb_set_auto_detach_kernel_driver@8 = libusb_set_auto_detach_kernel_driver - libusb_set_configuration - libusb_set_configuration@8 = libusb_set_configuration - libusb_set_debug - libusb_set_debug@8 = libusb_set_debug - libusb_set_interface_alt_setting - libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting - libusb_set_pollfd_notifiers - libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers - libusb_setlocale - libusb_setlocale@4 = libusb_setlocale - libusb_strerror - libusb_strerror@4 = libusb_strerror - libusb_submit_transfer - libusb_submit_transfer@4 = libusb_submit_transfer - libusb_try_lock_events - libusb_try_lock_events@4 = libusb_try_lock_events - libusb_unlock_event_waiters - libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters - libusb_unlock_events - libusb_unlock_events@4 = libusb_unlock_events - libusb_unref_device - libusb_unref_device@4 = libusb_unref_device - libusb_wait_for_event - libusb_wait_for_event@8 = libusb_wait_for_event diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/libusb-1.0.rc b/src/3rd_party-static/libusbx-1.0.16/libusb/libusb-1.0.rc deleted file mode 100644 index ae49757cc1..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/libusb-1.0.rc +++ /dev/null @@ -1,61 +0,0 @@ -/* - * For Windows: input this file to the Resoure Compiler to produce a binary - * .res file. This is then embedded in the resultant library (like any other - * compilation object). - * The information can then be queried using standard APIs and can also be - * viewed with utilities such as Windows Explorer. - */ -#ifndef _WIN32_WCE -#include "winresrc.h" -#endif - -#include "version.h" -#ifndef LIBUSB_VERSIONSTRING -#define LU_STR(s) #s -#define LU_XSTR(s) LU_STR(s) -#if LIBUSB_NANO > 0 -#define LIBUSB_VERSIONSTRING \ - LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." \ - LU_XSTR(LIBUSB_MICRO) "." LU_XSTR(LIBUSB_NANO) LIBUSB_RC "\0" -#else -#define LIBUSB_VERSIONSTRING \ - LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." \ - LU_XSTR(LIBUSB_MICRO) LIBUSB_RC "\0" -#endif -#endif - -VS_VERSION_INFO VERSIONINFO - FILEVERSION LIBUSB_MAJOR,LIBUSB_MINOR,LIBUSB_MICRO,LIBUSB_NANO - PRODUCTVERSION LIBUSB_MAJOR,LIBUSB_MINOR,LIBUSB_MICRO,LIBUSB_NANO - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "libusbx.org\0" - VALUE "FileDescription", "C library for writing portable USB drivers in userspace\0" - VALUE "FileVersion", LIBUSB_VERSIONSTRING - VALUE "InternalName", "libusb\0" - VALUE "LegalCopyright", "See individual source files, GNU LGPL v2.1 or later.\0" - VALUE "LegalTrademarks", "http://www.gnu.org/licenses/lgpl-2.1.html\0" - VALUE "OriginalFilename", "libusb-1.0.dll\0" - VALUE "PrivateBuild", "\0" - VALUE "ProductName", "libusb-1.0\0" - VALUE "ProductVersion", LIBUSB_VERSIONSTRING - VALUE "SpecialBuild", "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/libusb.h b/src/3rd_party-static/libusbx-1.0.16/libusb/libusb.h deleted file mode 100644 index e8e120162f..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/libusb.h +++ /dev/null @@ -1,1941 +0,0 @@ -/* - * Public libusbx header file - * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com> - * Copyright © 2007-2008 Daniel Drake <dsd@gentoo.org> - * Copyright © 2012 Pete Batard <pete@akeo.ie> - * Copyright © 2012 Nathan Hjelm <hjelmn@cs.unm.edu> - * For more information, please visit: http://libusbx.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 - */ - -#ifndef LIBUSB_H -#define LIBUSB_H - -#ifdef _MSC_VER -/* on MS environments, the inline keyword is available in C++ only */ -#if !defined(__cplusplus) -#define inline __inline -#endif -/* ssize_t is also not available (copy/paste from MinGW) */ -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#undef ssize_t -#ifdef _WIN64 - typedef __int64 ssize_t; -#else - typedef int ssize_t; -#endif /* _WIN64 */ -#endif /* _SSIZE_T_DEFINED */ -#endif /* _MSC_VER */ - -/* stdint.h is not available on older MSVC */ -#if defined(_MSC_VER) && (_MSC_VER < 1600) && (!defined(_STDINT)) && (!defined(_STDINT_H)) -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -#else -#include <stdint.h> -#endif - -#if !defined(_WIN32_WCE) -#include <sys/types.h> -#endif - -#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) -#include <sys/time.h> -#endif - -#include <time.h> -#include <limits.h> - -/* 'interface' might be defined as a macro on Windows, so we need to - * undefine it so as not to break the current libusbx API, because - * libusb_config_descriptor has an 'interface' member - * As this can be problematic if you include windows.h after libusb.h - * in your sources, we force windows.h to be included first. */ -#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) -#include <windows.h> -#if defined(interface) -#undef interface -#endif -#if !defined(__CYGWIN__) -#include <winsock.h> -#endif -#endif - -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) -#define LIBUSB_DEPRECATED_FOR(f) \ - __attribute__((deprecated("Use " #f " instead"))) -#else -#define LIBUSB_DEPRECATED_FOR(f) -#endif /* __GNUC__ */ - -/** \def LIBUSB_CALL - * \ingroup misc - * libusbx's Windows calling convention. - * - * Under Windows, the selection of available compilers and configurations - * means that, unlike other platforms, there is not <em>one true calling - * convention</em> (calling convention: the manner in which parameters are - * passed to funcions in the generated assembly code). - * - * Matching the Windows API itself, libusbx uses the WINAPI convention (which - * translates to the <tt>stdcall</tt> convention) and guarantees that the - * library is compiled in this way. The public header file also includes - * appropriate annotations so that your own software will use the right - * convention, even if another convention is being used by default within - * your codebase. - * - * The one consideration that you must apply in your software is to mark - * all functions which you use as libusbx callbacks with this LIBUSB_CALL - * annotation, so that they too get compiled for the correct calling - * convention. - * - * On non-Windows operating systems, this macro is defined as nothing. This - * means that you can apply it to your code without worrying about - * cross-platform compatibility. - */ -/* LIBUSB_CALL must be defined on both definition and declaration of libusbx - * functions. You'd think that declaration would be enough, but cygwin will - * complain about conflicting types unless both are marked this way. - * The placement of this macro is important too; it must appear after the - * return type, before the function name. See internal documentation for - * API_EXPORTED. - */ -#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) -#define LIBUSB_CALL WINAPI -#else -#define LIBUSB_CALL -#endif - -/** \def LIBUSBX_API_VERSION - * \ingroup misc - * libusbx's API version. - * - * Since version 1.0.13, to help with feature detection, libusbx defines - * a LIBUSBX_API_VERSION macro that gets increased every time there is a - * significant change to the API, such as the introduction of a new call, - * the definition of a new macro/enum member, or any other element that - * libusbx applications may want to detect at compilation time. - * - * The macro is typically used in an application as follows: - * \code - * #if defined(LIBUSBX_API_VERSION) && (LIBUSBX_API_VERSION >= 0x01001234) - * // Use one of the newer features from the libusbx API - * #endif - * \endcode - * - * Another feature of LIBUSBX_API_VERSION is that it can be used to detect - * whether you are compiling against the libusb or the libusbx library. - * - * Internally, LIBUSBX_API_VERSION is defined as follows: - * (libusbx major << 24) | (libusbx minor << 16) | (16 bit incremental) - */ -#define LIBUSBX_API_VERSION 0x01000102 - -#ifdef __cplusplus -extern "C" { -#endif - -/** \def libusb_cpu_to_le16 - * \ingroup misc - * Convert a 16-bit value from host-endian to little-endian format. On - * little endian systems, this function does nothing. On big endian systems, - * the bytes are swapped. - * \param x the host-endian value to convert - * \returns the value in little-endian byte order - */ -static inline uint16_t libusb_cpu_to_le16(const uint16_t x) -{ - union { - uint8_t b8[2]; - uint16_t b16; - } _tmp; - _tmp.b8[1] = (uint8_t) (x >> 8); - _tmp.b8[0] = (uint8_t) (x & 0xff); - return _tmp.b16; -} - -/** \def libusb_le16_to_cpu - * \ingroup misc - * Convert a 16-bit value from little-endian to host-endian format. On - * little endian systems, this function does nothing. On big endian systems, - * the bytes are swapped. - * \param x the little-endian value to convert - * \returns the value in host-endian byte order - */ -#define libusb_le16_to_cpu libusb_cpu_to_le16 - -/* standard USB stuff */ - -/** \ingroup desc - * Device and/or Interface Class codes */ -enum libusb_class_code { - /** In the context of a \ref libusb_device_descriptor "device descriptor", - * this bDeviceClass value indicates that each interface specifies its - * own class information and all interfaces operate independently. - */ - LIBUSB_CLASS_PER_INTERFACE = 0, - - /** Audio class */ - LIBUSB_CLASS_AUDIO = 1, - - /** Communications class */ - LIBUSB_CLASS_COMM = 2, - - /** Human Interface Device class */ - LIBUSB_CLASS_HID = 3, - - /** Physical */ - LIBUSB_CLASS_PHYSICAL = 5, - - /** Printer class */ - LIBUSB_CLASS_PRINTER = 7, - - /** Image class */ - LIBUSB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */ - LIBUSB_CLASS_IMAGE = 6, - - /** Mass storage class */ - LIBUSB_CLASS_MASS_STORAGE = 8, - - /** Hub class */ - LIBUSB_CLASS_HUB = 9, - - /** Data class */ - LIBUSB_CLASS_DATA = 10, - - /** Smart Card */ - LIBUSB_CLASS_SMART_CARD = 0x0b, - - /** Content Security */ - LIBUSB_CLASS_CONTENT_SECURITY = 0x0d, - - /** Video */ - LIBUSB_CLASS_VIDEO = 0x0e, - - /** Personal Healthcare */ - LIBUSB_CLASS_PERSONAL_HEALTHCARE = 0x0f, - - /** Diagnostic Device */ - LIBUSB_CLASS_DIAGNOSTIC_DEVICE = 0xdc, - - /** Wireless class */ - LIBUSB_CLASS_WIRELESS = 0xe0, - - /** Application class */ - LIBUSB_CLASS_APPLICATION = 0xfe, - - /** Class is vendor-specific */ - LIBUSB_CLASS_VENDOR_SPEC = 0xff -}; - -/** \ingroup desc - * Descriptor types as defined by the USB specification. */ -enum libusb_descriptor_type { - /** Device descriptor. See libusb_device_descriptor. */ - LIBUSB_DT_DEVICE = 0x01, - - /** Configuration descriptor. See libusb_config_descriptor. */ - LIBUSB_DT_CONFIG = 0x02, - - /** String descriptor */ - LIBUSB_DT_STRING = 0x03, - - /** Interface descriptor. See libusb_interface_descriptor. */ - LIBUSB_DT_INTERFACE = 0x04, - - /** Endpoint descriptor. See libusb_endpoint_descriptor. */ - LIBUSB_DT_ENDPOINT = 0x05, - - /** BOS descriptor */ - LIBUSB_DT_BOS = 0x0f, - - /** Device Capability descriptor */ - LIBUSB_DT_DEVICE_CAPABILITY = 0x10, - - /** HID descriptor */ - LIBUSB_DT_HID = 0x21, - - /** HID report descriptor */ - LIBUSB_DT_REPORT = 0x22, - - /** Physical descriptor */ - LIBUSB_DT_PHYSICAL = 0x23, - - /** Hub descriptor */ - LIBUSB_DT_HUB = 0x29, - - /** SuperSpeed Hub descriptor */ - LIBUSB_DT_SUPERSPEED_HUB = 0x2a, - - /** SuperSpeed Endpoint Companion descriptor */ - LIBUSB_DT_SS_ENDPOINT_COMPANION = 0x30 -}; - -/* Descriptor sizes per descriptor type */ -#define LIBUSB_DT_DEVICE_SIZE 18 -#define LIBUSB_DT_CONFIG_SIZE 9 -#define LIBUSB_DT_INTERFACE_SIZE 9 -#define LIBUSB_DT_ENDPOINT_SIZE 7 -#define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ -#define LIBUSB_DT_HUB_NONVAR_SIZE 7 -#define LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE 6 -#define LIBUSB_DT_BOS_SIZE 5 -#define LIBUSB_DT_DEVICE_CAPABILITY_SIZE 3 - -/* BOS descriptor sizes */ -#define LIBUSB_BT_USB_2_0_EXTENSION_SIZE 7 -#define LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE 10 -#define LIBUSB_BT_CONTAINER_ID_SIZE 20 - -/* We unwrap the BOS => define its max size */ -#define LIBUSB_DT_BOS_MAX_SIZE ((LIBUSB_DT_BOS_SIZE) +\ - (LIBUSB_BT_USB_2_0_EXTENSION_SIZE) +\ - (LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) +\ - (LIBUSB_BT_CONTAINER_ID_SIZE)) - -#define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ -#define LIBUSB_ENDPOINT_DIR_MASK 0x80 - -/** \ingroup desc - * Endpoint direction. Values for bit 7 of the - * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme. - */ -enum libusb_endpoint_direction { - /** In: device-to-host */ - LIBUSB_ENDPOINT_IN = 0x80, - - /** Out: host-to-device */ - LIBUSB_ENDPOINT_OUT = 0x00 -}; - -#define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */ - -/** \ingroup desc - * Endpoint transfer type. Values for bits 0:1 of the - * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field. - */ -enum libusb_transfer_type { - /** Control endpoint */ - LIBUSB_TRANSFER_TYPE_CONTROL = 0, - - /** Isochronous endpoint */ - LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1, - - /** Bulk endpoint */ - LIBUSB_TRANSFER_TYPE_BULK = 2, - - /** Interrupt endpoint */ - LIBUSB_TRANSFER_TYPE_INTERRUPT = 3 -}; - -/** \ingroup misc - * Standard requests, as defined in table 9-5 of the USB 3.0 specifications */ -enum libusb_standard_request { - /** Request status of the specific recipient */ - LIBUSB_REQUEST_GET_STATUS = 0x00, - - /** Clear or disable a specific feature */ - LIBUSB_REQUEST_CLEAR_FEATURE = 0x01, - - /* 0x02 is reserved */ - - /** Set or enable a specific feature */ - LIBUSB_REQUEST_SET_FEATURE = 0x03, - - /* 0x04 is reserved */ - - /** Set device address for all future accesses */ - LIBUSB_REQUEST_SET_ADDRESS = 0x05, - - /** Get the specified descriptor */ - LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06, - - /** Used to update existing descriptors or add new descriptors */ - LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07, - - /** Get the current device configuration value */ - LIBUSB_REQUEST_GET_CONFIGURATION = 0x08, - - /** Set device configuration */ - LIBUSB_REQUEST_SET_CONFIGURATION = 0x09, - - /** Return the selected alternate setting for the specified interface */ - LIBUSB_REQUEST_GET_INTERFACE = 0x0A, - - /** Select an alternate interface for the specified interface */ - LIBUSB_REQUEST_SET_INTERFACE = 0x0B, - - /** Set then report an endpoint's synchronization frame */ - LIBUSB_REQUEST_SYNCH_FRAME = 0x0C, - - /** Sets both the U1 and U2 Exit Latency */ - LIBUSB_REQUEST_SET_SEL = 0x30, - - /** Delay from the time a host transmits a packet to the time it is - * received by the device. */ - LIBUSB_SET_ISOCH_DELAY = 0x31, -}; - -/** \ingroup misc - * Request type bits of the - * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control - * transfers. */ -enum libusb_request_type { - /** Standard */ - LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5), - - /** Class */ - LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5), - - /** Vendor */ - LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5), - - /** Reserved */ - LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5) -}; - -/** \ingroup misc - * Recipient bits of the - * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control - * transfers. Values 4 through 31 are reserved. */ -enum libusb_request_recipient { - /** Device */ - LIBUSB_RECIPIENT_DEVICE = 0x00, - - /** Interface */ - LIBUSB_RECIPIENT_INTERFACE = 0x01, - - /** Endpoint */ - LIBUSB_RECIPIENT_ENDPOINT = 0x02, - - /** Other */ - LIBUSB_RECIPIENT_OTHER = 0x03, -}; - -#define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C - -/** \ingroup desc - * Synchronization type for isochronous endpoints. Values for bits 2:3 of the - * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in - * libusb_endpoint_descriptor. - */ -enum libusb_iso_sync_type { - /** No synchronization */ - LIBUSB_ISO_SYNC_TYPE_NONE = 0, - - /** Asynchronous */ - LIBUSB_ISO_SYNC_TYPE_ASYNC = 1, - - /** Adaptive */ - LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2, - - /** Synchronous */ - LIBUSB_ISO_SYNC_TYPE_SYNC = 3 -}; - -#define LIBUSB_ISO_USAGE_TYPE_MASK 0x30 - -/** \ingroup desc - * Usage type for isochronous endpoints. Values for bits 4:5 of the - * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in - * libusb_endpoint_descriptor. - */ -enum libusb_iso_usage_type { - /** Data endpoint */ - LIBUSB_ISO_USAGE_TYPE_DATA = 0, - - /** Feedback endpoint */ - LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1, - - /** Implicit feedback Data endpoint */ - LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2, -}; - -/** \ingroup desc - * A structure representing the standard USB device descriptor. This - * descriptor is documented in section 9.6.1 of the USB 3.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_device_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this - * context. */ - uint8_t bDescriptorType; - - /** USB specification release number in binary-coded decimal. A value of - * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */ - uint16_t bcdUSB; - - /** USB-IF class code for the device. See \ref libusb_class_code. */ - uint8_t bDeviceClass; - - /** USB-IF subclass code for the device, qualified by the bDeviceClass - * value */ - uint8_t bDeviceSubClass; - - /** USB-IF protocol code for the device, qualified by the bDeviceClass and - * bDeviceSubClass values */ - uint8_t bDeviceProtocol; - - /** Maximum packet size for endpoint 0 */ - uint8_t bMaxPacketSize0; - - /** USB-IF vendor ID */ - uint16_t idVendor; - - /** USB-IF product ID */ - uint16_t idProduct; - - /** Device release number in binary-coded decimal */ - uint16_t bcdDevice; - - /** Index of string descriptor describing manufacturer */ - uint8_t iManufacturer; - - /** Index of string descriptor describing product */ - uint8_t iProduct; - - /** Index of string descriptor containing device serial number */ - uint8_t iSerialNumber; - - /** Number of possible configurations */ - uint8_t bNumConfigurations; -}; - -/** \ingroup desc - * A structure representing the standard USB endpoint descriptor. This - * descriptor is documented in section 9.6.6 of the USB 3.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_endpoint_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in - * this context. */ - uint8_t bDescriptorType; - - /** The address of the endpoint described by this descriptor. Bits 0:3 are - * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction, - * see \ref libusb_endpoint_direction. - */ - uint8_t bEndpointAddress; - - /** Attributes which apply to the endpoint when it is configured using - * the bConfigurationValue. Bits 0:1 determine the transfer type and - * correspond to \ref libusb_transfer_type. Bits 2:3 are only used for - * isochronous endpoints and correspond to \ref libusb_iso_sync_type. - * Bits 4:5 are also only used for isochronous endpoints and correspond to - * \ref libusb_iso_usage_type. Bits 6:7 are reserved. - */ - uint8_t bmAttributes; - - /** Maximum packet size this endpoint is capable of sending/receiving. */ - uint16_t wMaxPacketSize; - - /** Interval for polling endpoint for data transfers. */ - uint8_t bInterval; - - /** For audio devices only: the rate at which synchronization feedback - * is provided. */ - uint8_t bRefresh; - - /** For audio devices only: the address if the synch endpoint */ - uint8_t bSynchAddress; - - /** Extra descriptors. If libusbx encounters unknown endpoint descriptors, - * it will store them here, should you wish to parse them. */ - const unsigned char *extra; - - /** Length of the extra descriptors, in bytes. */ - int extra_length; -}; - -/** \ingroup desc - * A structure representing the standard USB interface descriptor. This - * descriptor is documented in section 9.6.5 of the USB 3.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_interface_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE - * in this context. */ - uint8_t bDescriptorType; - - /** Number of this interface */ - uint8_t bInterfaceNumber; - - /** Value used to select this alternate setting for this interface */ - uint8_t bAlternateSetting; - - /** Number of endpoints used by this interface (excluding the control - * endpoint). */ - uint8_t bNumEndpoints; - - /** USB-IF class code for this interface. See \ref libusb_class_code. */ - uint8_t bInterfaceClass; - - /** USB-IF subclass code for this interface, qualified by the - * bInterfaceClass value */ - uint8_t bInterfaceSubClass; - - /** USB-IF protocol code for this interface, qualified by the - * bInterfaceClass and bInterfaceSubClass values */ - uint8_t bInterfaceProtocol; - - /** Index of string descriptor describing this interface */ - uint8_t iInterface; - - /** Array of endpoint descriptors. This length of this array is determined - * by the bNumEndpoints field. */ - const struct libusb_endpoint_descriptor *endpoint; - - /** Extra descriptors. If libusbx encounters unknown interface descriptors, - * it will store them here, should you wish to parse them. */ - const unsigned char *extra; - - /** Length of the extra descriptors, in bytes. */ - int extra_length; -}; - -/** \ingroup desc - * A collection of alternate settings for a particular USB interface. - */ -struct libusb_interface { - /** Array of interface descriptors. The length of this array is determined - * by the num_altsetting field. */ - const struct libusb_interface_descriptor *altsetting; - - /** The number of alternate settings that belong to this interface */ - int num_altsetting; -}; - -/** \ingroup desc - * A structure representing the standard USB configuration descriptor. This - * descriptor is documented in section 9.6.3 of the USB 3.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_config_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG - * in this context. */ - uint8_t bDescriptorType; - - /** Total length of data returned for this configuration */ - uint16_t wTotalLength; - - /** Number of interfaces supported by this configuration */ - uint8_t bNumInterfaces; - - /** Identifier value for this configuration */ - uint8_t bConfigurationValue; - - /** Index of string descriptor describing this configuration */ - uint8_t iConfiguration; - - /** Configuration characteristics */ - uint8_t bmAttributes; - - /** Maximum power consumption of the USB device from this bus in this - * configuration when the device is fully opreation. Expressed in units - * of 2 mA. */ - uint8_t MaxPower; - - /** Array of interfaces supported by this configuration. The length of - * this array is determined by the bNumInterfaces field. */ - const struct libusb_interface *interface; - - /** Extra descriptors. If libusbx encounters unknown configuration - * descriptors, it will store them here, should you wish to parse them. */ - const unsigned char *extra; - - /** Length of the extra descriptors, in bytes. */ - int extra_length; -}; - -/** \ingroup desc - * A structure representing the superspeed endpoint companion - * descriptor. This descriptor is documented in section 9.6.7 of - * the USB 3.0 specification. All multiple-byte fields are represented in - * host-endian format. - */ -struct libusb_ss_endpoint_companion_descriptor { - - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_SS_ENDPOINT_COMPANION in - * this context. */ - uint8_t bDescriptorType; - - - /** The maximum number of packets the endpoint can send or - * recieve as part of a burst. */ - uint8_t bMaxBurst; - - /** In bulk EP: bits 4:0 represents the maximum number of - * streams the EP supports. In isochronous EP: bits 1:0 - * represents the Mult - a zero based value that determines - * the maximum number of packets within a service interval */ - uint8_t bmAttributes; - - /** The total number of bytes this EP will transfer every - * service interval. valid only for periodic EPs. */ - uint16_t wBytesPerInterval; -}; - -/** \ingroup desc - * A generic representation of a BOS Device Capability descriptor. It is - * advised to check bDevCapabilityType and call the matching - * libusb_get_*_descriptor function to get a structure fully matching the type. - */ -struct libusb_bos_dev_capability_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY - * LIBUSB_DT_DEVICE_CAPABILITY in this context. */ - uint8_t bDescriptorType; - /** Device Capability type */ - uint8_t bDevCapabilityType; - /** Device Capability data (bLength - 3 bytes) */ - uint8_t dev_capability_data -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif - ; -}; - -/** \ingroup desc - * A structure representing the Binary Device Object Store (BOS) descriptor. - * This descriptor is documented in section 9.6.2 of the USB 3.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_bos_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_BOS LIBUSB_DT_BOS - * in this context. */ - uint8_t bDescriptorType; - - /** Length of this descriptor and all of its sub descriptors */ - uint16_t wTotalLength; - - /** The number of separate device capability descriptors in - * the BOS */ - uint8_t bNumDeviceCaps; - - /** bNumDeviceCap Device Capability Descriptors */ - struct libusb_bos_dev_capability_descriptor *dev_capability -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif - ; -}; - -/** \ingroup desc - * A structure representing the USB 2.0 Extension descriptor - * This descriptor is documented in section 9.6.2.1 of the USB 3.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_usb_2_0_extension_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY - * LIBUSB_DT_DEVICE_CAPABILITY in this context. */ - uint8_t bDescriptorType; - - /** Capability type. Will have value - * \ref libusb_capability_type::LIBUSB_BT_USB_2_0_EXTENSION - * LIBUSB_BT_USB_2_0_EXTENSION in this context. */ - uint8_t bDevCapabilityType; - - /** Bitmap encoding of supported device level features. - * A value of one in a bit location indicates a feature is - * supported; a value of zero indicates it is not supported. - * See \ref libusb_usb_2_0_extension_attributes. */ - uint32_t bmAttributes; -}; - -/** \ingroup desc - * A structure representing the SuperSpeed USB Device Capability descriptor - * This descriptor is documented in section 9.6.2.2 of the USB 3.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_ss_usb_device_capability_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY - * LIBUSB_DT_DEVICE_CAPABILITY in this context. */ - uint8_t bDescriptorType; - - /** Capability type. Will have value - * \ref libusb_capability_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY - * LIBUSB_BT_SS_USB_DEVICE_CAPABILITY in this context. */ - uint8_t bDevCapabilityType; - - /** Bitmap encoding of supported device level features. - * A value of one in a bit location indicates a feature is - * supported; a value of zero indicates it is not supported. - * See \ref libusb_ss_usb_device_capability_attributes. */ - uint8_t bmAttributes; - - /** Bitmap encoding of the speed supported by this device when - * operating in SuperSpeed mode. See \ref libusb_supported_speed. */ - uint16_t wSpeedSupported; - - /** The lowest speed at which all the functionality supported - * by the device is available to the user. For example if the - * device supports all its functionality when connected at - * full speed and above then it sets this value to 1. */ - uint8_t bFunctionalitySupport; - - /** U1 Device Exit Latency. */ - uint8_t bU1DevExitLat; - - /** U2 Device Exit Latency. */ - uint16_t bU2DevExitLat; -}; - -/** \ingroup desc - * A structure representing the Container ID descriptor. - * This descriptor is documented in section 9.6.2.3 of the USB 3.0 specification. - * All multiple-byte fields, except UUIDs, are represented in host-endian format. - */ -struct libusb_container_id_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY - * LIBUSB_DT_DEVICE_CAPABILITY in this context. */ - uint8_t bDescriptorType; - - /** Capability type. Will have value - * \ref libusb_capability_type::LIBUSB_BT_CONTAINER_ID - * LIBUSB_BT_CONTAINER_ID in this context. */ - uint8_t bDevCapabilityType; - - /** Reserved field */ - uint8_t bReserved; - - /** 128 bit UUID */ - uint8_t ContainerID[16]; -}; - -/** \ingroup asyncio - * Setup packet for control transfers. */ -struct libusb_control_setup { - /** Request type. Bits 0:4 determine recipient, see - * \ref libusb_request_recipient. Bits 5:6 determine type, see - * \ref libusb_request_type. Bit 7 determines data transfer direction, see - * \ref libusb_endpoint_direction. - */ - uint8_t bmRequestType; - - /** Request. If the type bits of bmRequestType are equal to - * \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD - * "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to - * \ref libusb_standard_request. For other cases, use of this field is - * application-specific. */ - uint8_t bRequest; - - /** Value. Varies according to request */ - uint16_t wValue; - - /** Index. Varies according to request, typically used to pass an index - * or offset */ - uint16_t wIndex; - - /** Number of bytes to transfer */ - uint16_t wLength; -}; - -#define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup)) - -/* libusbx */ - -struct libusb_context; -struct libusb_device; -struct libusb_device_handle; -struct libusb_hotplug_callback; - -/** \ingroup lib - * Structure providing the version of the libusbx runtime - */ -struct libusb_version { - /** Library major version. */ - const uint16_t major; - - /** Library minor version. */ - const uint16_t minor; - - /** Library micro version. */ - const uint16_t micro; - - /** Library nano version. */ - const uint16_t nano; - - /** Library release candidate suffix string, e.g. "-rc4". */ - const char *rc; - - /** For ABI compatibility only. */ - const char* describe; -}; - -/** \ingroup lib - * Structure representing a libusbx session. The concept of individual libusbx - * sessions allows for your program to use two libraries (or dynamically - * load two modules) which both independently use libusb. This will prevent - * interference between the individual libusbx users - for example - * libusb_set_debug() will not affect the other user of the library, and - * libusb_exit() will not destroy resources that the other user is still - * using. - * - * Sessions are created by libusb_init() and destroyed through libusb_exit(). - * If your application is guaranteed to only ever include a single libusbx - * user (i.e. you), you do not have to worry about contexts: pass NULL in - * every function call where a context is required. The default context - * will be used. - * - * For more information, see \ref contexts. - */ -typedef struct libusb_context libusb_context; - -/** \ingroup dev - * Structure representing a USB device detected on the system. This is an - * opaque type for which you are only ever provided with a pointer, usually - * originating from libusb_get_device_list(). - * - * Certain operations can be performed on a device, but in order to do any - * I/O you will have to first obtain a device handle using libusb_open(). - * - * Devices are reference counted with libusb_ref_device() and - * libusb_unref_device(), and are freed when the reference count reaches 0. - * New devices presented by libusb_get_device_list() have a reference count of - * 1, and libusb_free_device_list() can optionally decrease the reference count - * on all devices in the list. libusb_open() adds another reference which is - * later destroyed by libusb_close(). - */ -typedef struct libusb_device libusb_device; - - -/** \ingroup dev - * Structure representing a handle on a USB device. This is an opaque type for - * which you are only ever provided with a pointer, usually originating from - * libusb_open(). - * - * A device handle is used to perform I/O and other operations. When finished - * with a device handle, you should call libusb_close(). - */ -typedef struct libusb_device_handle libusb_device_handle; - -/** \ingroup dev - * Speed codes. Indicates the speed at which the device is operating. - */ -enum libusb_speed { - /** The OS doesn't report or know the device speed. */ - LIBUSB_SPEED_UNKNOWN = 0, - - /** The device is operating at low speed (1.5MBit/s). */ - LIBUSB_SPEED_LOW = 1, - - /** The device is operating at full speed (12MBit/s). */ - LIBUSB_SPEED_FULL = 2, - - /** The device is operating at high speed (480MBit/s). */ - LIBUSB_SPEED_HIGH = 3, - - /** The device is operating at super speed (5000MBit/s). */ - LIBUSB_SPEED_SUPER = 4, -}; - -/** \ingroup dev - * Supported speeds (wSpeedSupported) bitfield. Indicates what - * speeds the device supports. - */ -enum libusb_supported_speed { - /** Low speed operation supported (1.5MBit/s). */ - LIBUSB_LOW_SPEED_OPERATION = 1, - - /** Full speed operation supported (12MBit/s). */ - LIBUSB_FULL_SPEED_OPERATION = 2, - - /** High speed operation supported (480MBit/s). */ - LIBUSB_HIGH_SPEED_OPERATION = 4, - - /** Superspeed operation supported (5000MBit/s). */ - LIBUSB_SUPER_SPEED_OPERATION = 8, -}; - -/** \ingroup dev - * Masks for the bits of the - * \ref libusb_usb_2_0_extension_descriptor::bmAttributes "bmAttributes" field - * of the USB 2.0 Extension descriptor. - */ -enum libusb_usb_2_0_extension_attributes { - /** Supports Link Power Management (LPM) */ - LIBUSB_BM_LPM_SUPPORT = 2, -}; - -/** \ingroup dev - * Masks for the bits of the - * \ref libusb_ss_usb_device_capability_descriptor::bmAttributes "bmAttributes" field - * field of the SuperSpeed USB Device Capability descriptor. - */ -enum libusb_ss_usb_device_capability_attributes { - /** Supports Latency Tolerance Messages (LTM) */ - LIBUSB_BM_LTM_SUPPORT = 2, -}; - -/** \ingroup dev - * USB capability types - */ -enum libusb_bos_type { - /** Wireless USB device capability */ - LIBUSB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1, - - /** USB 2.0 extensions */ - LIBUSB_BT_USB_2_0_EXTENSION = 2, - - /** SuperSpeed USB device capability */ - LIBUSB_BT_SS_USB_DEVICE_CAPABILITY = 3, - - /** Container ID type */ - LIBUSB_BT_CONTAINER_ID = 4, -}; - -/** \ingroup misc - * Error codes. Most libusbx functions return 0 on success or one of these - * codes on failure. - * You can call libusb_error_name() to retrieve a string representation of an - * error code or libusb_strerror() to get an end-user suitable description of - * an error code. - */ -enum libusb_error { - /** Success (no error) */ - LIBUSB_SUCCESS = 0, - - /** Input/output error */ - LIBUSB_ERROR_IO = -1, - - /** Invalid parameter */ - LIBUSB_ERROR_INVALID_PARAM = -2, - - /** Access denied (insufficient permissions) */ - LIBUSB_ERROR_ACCESS = -3, - - /** No such device (it may have been disconnected) */ - LIBUSB_ERROR_NO_DEVICE = -4, - - /** Entity not found */ - LIBUSB_ERROR_NOT_FOUND = -5, - - /** Resource busy */ - LIBUSB_ERROR_BUSY = -6, - - /** Operation timed out */ - LIBUSB_ERROR_TIMEOUT = -7, - - /** Overflow */ - LIBUSB_ERROR_OVERFLOW = -8, - - /** Pipe error */ - LIBUSB_ERROR_PIPE = -9, - - /** System call interrupted (perhaps due to signal) */ - LIBUSB_ERROR_INTERRUPTED = -10, - - /** Insufficient memory */ - LIBUSB_ERROR_NO_MEM = -11, - - /** Operation not supported or unimplemented on this platform */ - LIBUSB_ERROR_NOT_SUPPORTED = -12, - - /* NB: Remember to update LIBUSB_ERROR_COUNT below as well as the - message strings in strerror.c when adding new error codes here. */ - - /** Other error */ - LIBUSB_ERROR_OTHER = -99, -}; - -/* Total number of error codes in enum libusb_error */ -#define LIBUSB_ERROR_COUNT 14 - -/** \ingroup asyncio - * Transfer status codes */ -enum libusb_transfer_status { - /** Transfer completed without error. Note that this does not indicate - * that the entire amount of requested data was transferred. */ - LIBUSB_TRANSFER_COMPLETED, - - /** Transfer failed */ - LIBUSB_TRANSFER_ERROR, - - /** Transfer timed out */ - LIBUSB_TRANSFER_TIMED_OUT, - - /** Transfer was cancelled */ - LIBUSB_TRANSFER_CANCELLED, - - /** For bulk/interrupt endpoints: halt condition detected (endpoint - * stalled). For control endpoints: control request not supported. */ - LIBUSB_TRANSFER_STALL, - - /** Device was disconnected */ - LIBUSB_TRANSFER_NO_DEVICE, - - /** Device sent more data than requested */ - LIBUSB_TRANSFER_OVERFLOW, - - /* NB! Remember to update libusb_error_name() - when adding new status codes here. */ -}; - -/** \ingroup asyncio - * libusb_transfer.flags values */ -enum libusb_transfer_flags { - /** Report short frames as errors */ - LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0, - - /** Automatically free() transfer buffer during libusb_free_transfer() */ - LIBUSB_TRANSFER_FREE_BUFFER = 1<<1, - - /** Automatically call libusb_free_transfer() after callback returns. - * If this flag is set, it is illegal to call libusb_free_transfer() - * from your transfer callback, as this will result in a double-free - * when this flag is acted upon. */ - LIBUSB_TRANSFER_FREE_TRANSFER = 1<<2, - - /** Terminate transfers that are a multiple of the endpoint's - * wMaxPacketSize with an extra zero length packet. This is useful - * when a device protocol mandates that each logical request is - * terminated by an incomplete packet (i.e. the logical requests are - * not separated by other means). - * - * This flag only affects host-to-device transfers to bulk and interrupt - * endpoints. In other situations, it is ignored. - * - * This flag only affects transfers with a length that is a multiple of - * the endpoint's wMaxPacketSize. On transfers of other lengths, this - * flag has no effect. Therefore, if you are working with a device that - * needs a ZLP whenever the end of the logical request falls on a packet - * boundary, then it is sensible to set this flag on <em>every</em> - * transfer (you do not have to worry about only setting it on transfers - * that end on the boundary). - * - * This flag is currently only supported on Linux. - * On other systems, libusb_submit_transfer() will return - * LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set. - * - * Available since libusb-1.0.9. - */ - LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3, -}; - -/** \ingroup asyncio - * Isochronous packet descriptor. */ -struct libusb_iso_packet_descriptor { - /** Length of data to request in this packet */ - unsigned int length; - - /** Amount of data that was actually transferred */ - unsigned int actual_length; - - /** Status code for this packet */ - enum libusb_transfer_status status; -}; - -struct libusb_transfer; - -/** \ingroup asyncio - * Asynchronous transfer callback function type. When submitting asynchronous - * transfers, you pass a pointer to a callback function of this type via the - * \ref libusb_transfer::callback "callback" member of the libusb_transfer - * structure. libusbx will call this function later, when the transfer has - * completed or failed. See \ref asyncio for more information. - * \param transfer The libusb_transfer struct the callback function is being - * notified about. - */ -typedef void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer); - -/** \ingroup asyncio - * The generic USB transfer structure. The user populates this structure and - * then submits it in order to request a transfer. After the transfer has - * completed, the library populates the transfer with the results and passes - * it back to the user. - */ -struct libusb_transfer { - /** Handle of the device that this transfer will be submitted to */ - libusb_device_handle *dev_handle; - - /** A bitwise OR combination of \ref libusb_transfer_flags. */ - uint8_t flags; - - /** Address of the endpoint where this transfer will be sent. */ - unsigned char endpoint; - - /** Type of the endpoint from \ref libusb_transfer_type */ - unsigned char type; - - /** Timeout for this transfer in millseconds. A value of 0 indicates no - * timeout. */ - unsigned int timeout; - - /** The status of the transfer. Read-only, and only for use within - * transfer callback function. - * - * If this is an isochronous transfer, this field may read COMPLETED even - * if there were errors in the frames. Use the - * \ref libusb_iso_packet_descriptor::status "status" field in each packet - * to determine if errors occurred. */ - enum libusb_transfer_status status; - - /** Length of the data buffer */ - int length; - - /** Actual length of data that was transferred. Read-only, and only for - * use within transfer callback function. Not valid for isochronous - * endpoint transfers. */ - int actual_length; - - /** Callback function. This will be invoked when the transfer completes, - * fails, or is cancelled. */ - libusb_transfer_cb_fn callback; - - /** User context data to pass to the callback function. */ - void *user_data; - - /** Data buffer */ - unsigned char *buffer; - - /** Number of isochronous packets. Only used for I/O with isochronous - * endpoints. */ - int num_iso_packets; - - /** Isochronous packet descriptors, for isochronous transfers only. */ - struct libusb_iso_packet_descriptor iso_packet_desc -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif - ; -}; - -/** \ingroup misc - * Capabilities supported by an instance of libusb on the current running - * platform. Test if the loaded library supports a given capability by calling - * \ref libusb_has_capability(). - */ -enum libusb_capability { - /** The libusb_has_capability() API is available. */ - LIBUSB_CAP_HAS_CAPABILITY = 0x0000, - /** Hotplug support is available on this platform. */ - LIBUSB_CAP_HAS_HOTPLUG = 0x0001, - /** The library can access HID devices without requiring user intervention. - * Note that before being able to actually access an HID device, you may - * still have to call additional libusbx functions such as - * \ref libusb_detach_kernel_driver(). */ - LIBUSB_CAP_HAS_HID_ACCESS = 0x0100, - /** The library supports detaching of the default USB driver, using - * \ref libusb_detach_kernel_driver(), if one is set by the OS kernel */ - LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER = 0x0101 -}; - -/** \ingroup lib - * Log message levels. - * - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default) - * - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr - * - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr - * - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stdout, warning - * and error messages are printed to stderr - * - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stdout, - * warnings and errors to stderr - */ -enum libusb_log_level { - LIBUSB_LOG_LEVEL_NONE = 0, - LIBUSB_LOG_LEVEL_ERROR, - LIBUSB_LOG_LEVEL_WARNING, - LIBUSB_LOG_LEVEL_INFO, - LIBUSB_LOG_LEVEL_DEBUG, -}; - -int LIBUSB_CALL libusb_init(libusb_context **ctx); -void LIBUSB_CALL libusb_exit(libusb_context *ctx); -void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level); -const struct libusb_version * LIBUSB_CALL libusb_get_version(void); -int LIBUSB_CALL libusb_has_capability(uint32_t capability); -const char * LIBUSB_CALL libusb_error_name(int errcode); -int LIBUSB_CALL libusb_setlocale(const char *locale); -const char * LIBUSB_CALL libusb_strerror(enum libusb_error errcode); - -ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx, - libusb_device ***list); -void LIBUSB_CALL libusb_free_device_list(libusb_device **list, - int unref_devices); -libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev); -void LIBUSB_CALL libusb_unref_device(libusb_device *dev); - -int LIBUSB_CALL libusb_get_configuration(libusb_device_handle *dev, - int *config); -int LIBUSB_CALL libusb_get_device_descriptor(libusb_device *dev, - struct libusb_device_descriptor *desc); -int LIBUSB_CALL libusb_get_active_config_descriptor(libusb_device *dev, - struct libusb_config_descriptor **config); -int LIBUSB_CALL libusb_get_config_descriptor(libusb_device *dev, - uint8_t config_index, struct libusb_config_descriptor **config); -int LIBUSB_CALL libusb_get_config_descriptor_by_value(libusb_device *dev, - uint8_t bConfigurationValue, struct libusb_config_descriptor **config); -void LIBUSB_CALL libusb_free_config_descriptor( - struct libusb_config_descriptor *config); -int LIBUSB_CALL libusb_get_ss_endpoint_companion_descriptor( - struct libusb_context *ctx, - const struct libusb_endpoint_descriptor *endpoint, - struct libusb_ss_endpoint_companion_descriptor **ep_comp); -void LIBUSB_CALL libusb_free_ss_endpoint_companion_descriptor( - struct libusb_ss_endpoint_companion_descriptor *ep_comp); -int LIBUSB_CALL libusb_get_bos_descriptor(libusb_device_handle *handle, - struct libusb_bos_descriptor **bos); -void LIBUSB_CALL libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos); -int LIBUSB_CALL 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); -void LIBUSB_CALL libusb_free_usb_2_0_extension_descriptor( - struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension); -int LIBUSB_CALL 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); -void LIBUSB_CALL libusb_free_ss_usb_device_capability_descriptor( - struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap); -int LIBUSB_CALL libusb_get_container_id_descriptor(struct libusb_context *ctx, - struct libusb_bos_dev_capability_descriptor *dev_cap, - struct libusb_container_id_descriptor **container_id); -void LIBUSB_CALL libusb_free_container_id_descriptor( - struct libusb_container_id_descriptor *container_id); -uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev); -uint8_t LIBUSB_CALL libusb_get_port_number(libusb_device *dev); -int LIBUSB_CALL libusb_get_port_numbers(libusb_device *dev, uint8_t* port_numbers, int port_numbers_len); -LIBUSB_DEPRECATED_FOR(libusb_get_port_numbers) -int LIBUSB_CALL libusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t* path, uint8_t path_length); -libusb_device * LIBUSB_CALL libusb_get_parent(libusb_device *dev); -uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device *dev); -int LIBUSB_CALL libusb_get_device_speed(libusb_device *dev); -int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev, - unsigned char endpoint); -int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev, - unsigned char endpoint); - -int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle); -void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle); -libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle); - -int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev, - int configuration); -int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev, - int interface_number); -int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev, - int interface_number); - -libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( - libusb_context *ctx, uint16_t vendor_id, uint16_t product_id); - -int LIBUSB_CALL libusb_set_interface_alt_setting(libusb_device_handle *dev, - int interface_number, int alternate_setting); -int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev, - unsigned char endpoint); -int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev); - -int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev, - int interface_number); -int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev, - int interface_number); -int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev, - int interface_number); -int LIBUSB_CALL libusb_set_auto_detach_kernel_driver( - libusb_device_handle *dev, int enable); - -/* async I/O */ - -/** \ingroup asyncio - * Get the data section of a control transfer. This convenience function is here - * to remind you that the data does not start until 8 bytes into the actual - * buffer, as the setup packet comes first. - * - * Calling this function only makes sense from a transfer callback function, - * or situations where you have already allocated a suitably sized buffer at - * transfer->buffer. - * - * \param transfer a transfer - * \returns pointer to the first byte of the data section - */ -static inline unsigned char *libusb_control_transfer_get_data( - struct libusb_transfer *transfer) -{ - return transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; -} - -/** \ingroup asyncio - * Get the control setup packet of a control transfer. This convenience - * function is here to remind you that the control setup occupies the first - * 8 bytes of the transfer data buffer. - * - * Calling this function only makes sense from a transfer callback function, - * or situations where you have already allocated a suitably sized buffer at - * transfer->buffer. - * - * \param transfer a transfer - * \returns a casted pointer to the start of the transfer data buffer - */ -static inline struct libusb_control_setup *libusb_control_transfer_get_setup( - struct libusb_transfer *transfer) -{ - return (struct libusb_control_setup *) transfer->buffer; -} - -/** \ingroup asyncio - * Helper function to populate the setup packet (first 8 bytes of the data - * buffer) for a control transfer. The wIndex, wValue and wLength values should - * be given in host-endian byte order. - * - * \param buffer buffer to output the setup packet into - * \param bmRequestType see the - * \ref libusb_control_setup::bmRequestType "bmRequestType" field of - * \ref libusb_control_setup - * \param bRequest see the - * \ref libusb_control_setup::bRequest "bRequest" field of - * \ref libusb_control_setup - * \param wValue see the - * \ref libusb_control_setup::wValue "wValue" field of - * \ref libusb_control_setup - * \param wIndex see the - * \ref libusb_control_setup::wIndex "wIndex" field of - * \ref libusb_control_setup - * \param wLength see the - * \ref libusb_control_setup::wLength "wLength" field of - * \ref libusb_control_setup - */ -static inline void libusb_fill_control_setup(unsigned char *buffer, - uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - uint16_t wLength) -{ - struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; - setup->bmRequestType = bmRequestType; - setup->bRequest = bRequest; - setup->wValue = libusb_cpu_to_le16(wValue); - setup->wIndex = libusb_cpu_to_le16(wIndex); - setup->wLength = libusb_cpu_to_le16(wLength); -} - -struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(int iso_packets); -int LIBUSB_CALL libusb_submit_transfer(struct libusb_transfer *transfer); -int LIBUSB_CALL libusb_cancel_transfer(struct libusb_transfer *transfer); -void LIBUSB_CALL libusb_free_transfer(struct libusb_transfer *transfer); - -/** \ingroup asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for a control transfer. - * - * If you pass a transfer buffer to this function, the first 8 bytes will - * be interpreted as a control setup packet, and the wLength field will be - * used to automatically populate the \ref libusb_transfer::length "length" - * field of the transfer. Therefore the recommended approach is: - * -# Allocate a suitably sized data buffer (including space for control setup) - * -# Call libusb_fill_control_setup() - * -# If this is a host-to-device transfer with a data stage, put the data - * in place after the setup packet - * -# Call this function - * -# Call libusb_submit_transfer() - * - * It is also legal to pass a NULL buffer to this function, in which case this - * function will not attempt to populate the length field. Remember that you - * must then populate the buffer and length fields later. - * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param buffer data buffer. If provided, this function will interpret the - * first 8 bytes as a setup packet and infer the transfer length from that. - * \param callback callback function to be invoked on transfer completion - * \param user_data user data to pass to callback function - * \param timeout timeout for the transfer in milliseconds - */ -static inline void libusb_fill_control_transfer( - struct libusb_transfer *transfer, libusb_device_handle *dev_handle, - unsigned char *buffer, libusb_transfer_cb_fn callback, void *user_data, - unsigned int timeout) -{ - struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; - transfer->dev_handle = dev_handle; - transfer->endpoint = 0; - transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL; - transfer->timeout = timeout; - transfer->buffer = buffer; - if (setup) - transfer->length = (int) (LIBUSB_CONTROL_SETUP_SIZE - + libusb_le16_to_cpu(setup->wLength)); - transfer->user_data = user_data; - transfer->callback = callback; -} - -/** \ingroup asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for a bulk transfer. - * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param endpoint address of the endpoint where this transfer will be sent - * \param buffer data buffer - * \param length length of data buffer - * \param callback callback function to be invoked on transfer completion - * \param user_data user data to pass to callback function - * \param timeout timeout for the transfer in milliseconds - */ -static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, - libusb_device_handle *dev_handle, unsigned char endpoint, - unsigned char *buffer, int length, libusb_transfer_cb_fn callback, - void *user_data, unsigned int timeout) -{ - transfer->dev_handle = dev_handle; - transfer->endpoint = endpoint; - transfer->type = LIBUSB_TRANSFER_TYPE_BULK; - transfer->timeout = timeout; - transfer->buffer = buffer; - transfer->length = length; - transfer->user_data = user_data; - transfer->callback = callback; -} - -/** \ingroup asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for an interrupt transfer. - * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param endpoint address of the endpoint where this transfer will be sent - * \param buffer data buffer - * \param length length of data buffer - * \param callback callback function to be invoked on transfer completion - * \param user_data user data to pass to callback function - * \param timeout timeout for the transfer in milliseconds - */ -static inline void libusb_fill_interrupt_transfer( - struct libusb_transfer *transfer, libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *buffer, int length, - libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) -{ - transfer->dev_handle = dev_handle; - transfer->endpoint = endpoint; - transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; - transfer->timeout = timeout; - transfer->buffer = buffer; - transfer->length = length; - transfer->user_data = user_data; - transfer->callback = callback; -} - -/** \ingroup asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for an isochronous transfer. - * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param endpoint address of the endpoint where this transfer will be sent - * \param buffer data buffer - * \param length length of data buffer - * \param num_iso_packets the number of isochronous packets - * \param callback callback function to be invoked on transfer completion - * \param user_data user data to pass to callback function - * \param timeout timeout for the transfer in milliseconds - */ -static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer, - libusb_device_handle *dev_handle, unsigned char endpoint, - unsigned char *buffer, int length, int num_iso_packets, - libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) -{ - transfer->dev_handle = dev_handle; - transfer->endpoint = endpoint; - transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS; - transfer->timeout = timeout; - transfer->buffer = buffer; - transfer->length = length; - transfer->num_iso_packets = num_iso_packets; - transfer->user_data = user_data; - transfer->callback = callback; -} - -/** \ingroup asyncio - * Convenience function to set the length of all packets in an isochronous - * transfer, based on the num_iso_packets field in the transfer structure. - * - * \param transfer a transfer - * \param length the length to set in each isochronous packet descriptor - * \see libusb_get_max_packet_size() - */ -static inline void libusb_set_iso_packet_lengths( - struct libusb_transfer *transfer, unsigned int length) -{ - int i; - for (i = 0; i < transfer->num_iso_packets; i++) - transfer->iso_packet_desc[i].length = length; -} - -/** \ingroup asyncio - * Convenience function to locate the position of an isochronous packet - * within the buffer of an isochronous transfer. - * - * This is a thorough function which loops through all preceding packets, - * accumulating their lengths to find the position of the specified packet. - * Typically you will assign equal lengths to each packet in the transfer, - * and hence the above method is sub-optimal. You may wish to use - * libusb_get_iso_packet_buffer_simple() instead. - * - * \param transfer a transfer - * \param packet the packet to return the address of - * \returns the base address of the packet buffer inside the transfer buffer, - * or NULL if the packet does not exist. - * \see libusb_get_iso_packet_buffer_simple() - */ -static inline unsigned char *libusb_get_iso_packet_buffer( - struct libusb_transfer *transfer, unsigned int packet) -{ - int i; - size_t offset = 0; - int _packet; - - /* oops..slight bug in the API. packet is an unsigned int, but we use - * signed integers almost everywhere else. range-check and convert to - * signed to avoid compiler warnings. FIXME for libusb-2. */ - if (packet > INT_MAX) - return NULL; - _packet = (int) packet; - - if (_packet >= transfer->num_iso_packets) - return NULL; - - for (i = 0; i < _packet; i++) - offset += transfer->iso_packet_desc[i].length; - - return transfer->buffer + offset; -} - -/** \ingroup asyncio - * Convenience function to locate the position of an isochronous packet - * within the buffer of an isochronous transfer, for transfers where each - * packet is of identical size. - * - * This function relies on the assumption that every packet within the transfer - * is of identical size to the first packet. Calculating the location of - * the packet buffer is then just a simple calculation: - * <tt>buffer + (packet_size * packet)</tt> - * - * Do not use this function on transfers other than those that have identical - * packet lengths for each packet. - * - * \param transfer a transfer - * \param packet the packet to return the address of - * \returns the base address of the packet buffer inside the transfer buffer, - * or NULL if the packet does not exist. - * \see libusb_get_iso_packet_buffer() - */ -static inline unsigned char *libusb_get_iso_packet_buffer_simple( - struct libusb_transfer *transfer, unsigned int packet) -{ - int _packet; - - /* oops..slight bug in the API. packet is an unsigned int, but we use - * signed integers almost everywhere else. range-check and convert to - * signed to avoid compiler warnings. FIXME for libusb-2. */ - if (packet > INT_MAX) - return NULL; - _packet = (int) packet; - - if (_packet >= transfer->num_iso_packets) - return NULL; - - return transfer->buffer + ((int) transfer->iso_packet_desc[0].length * _packet); -} - -/* sync I/O */ - -int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle, - uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - unsigned char *data, uint16_t wLength, unsigned int timeout); - -int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *data, int length, - int *actual_length, unsigned int timeout); - -int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *data, int length, - int *actual_length, unsigned int timeout); - -/** \ingroup desc - * Retrieve a descriptor from the default control pipe. - * This is a convenience function which formulates the appropriate control - * message to retrieve the descriptor. - * - * \param dev a device handle - * \param desc_type the descriptor type, see \ref libusb_descriptor_type - * \param desc_index the index of the descriptor to retrieve - * \param data output buffer for descriptor - * \param length size of data buffer - * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure - */ -static inline int libusb_get_descriptor(libusb_device_handle *dev, - uint8_t desc_type, uint8_t desc_index, unsigned char *data, int length) -{ - return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, - LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t) ((desc_type << 8) | desc_index), - 0, data, (uint16_t) length, 1000); -} - -/** \ingroup desc - * Retrieve a descriptor from a device. - * This is a convenience function which formulates the appropriate control - * message to retrieve the descriptor. The string returned is Unicode, as - * detailed in the USB specifications. - * - * \param dev a device handle - * \param desc_index the index of the descriptor to retrieve - * \param langid the language ID for the string descriptor - * \param data output buffer for descriptor - * \param length size of data buffer - * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure - * \see libusb_get_string_descriptor_ascii() - */ -static inline int libusb_get_string_descriptor(libusb_device_handle *dev, - uint8_t desc_index, uint16_t langid, unsigned char *data, int length) -{ - return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, - LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t)((LIBUSB_DT_STRING << 8) | desc_index), - langid, data, (uint16_t) length, 1000); -} - -int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev, - uint8_t desc_index, unsigned char *data, int length); - -/* polling and timeouts */ - -int LIBUSB_CALL libusb_try_lock_events(libusb_context *ctx); -void LIBUSB_CALL libusb_lock_events(libusb_context *ctx); -void LIBUSB_CALL libusb_unlock_events(libusb_context *ctx); -int LIBUSB_CALL libusb_event_handling_ok(libusb_context *ctx); -int LIBUSB_CALL libusb_event_handler_active(libusb_context *ctx); -void LIBUSB_CALL libusb_lock_event_waiters(libusb_context *ctx); -void LIBUSB_CALL libusb_unlock_event_waiters(libusb_context *ctx); -int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv); - -int LIBUSB_CALL libusb_handle_events_timeout(libusb_context *ctx, - struct timeval *tv); -int LIBUSB_CALL libusb_handle_events_timeout_completed(libusb_context *ctx, - struct timeval *tv, int *completed); -int LIBUSB_CALL libusb_handle_events(libusb_context *ctx); -int LIBUSB_CALL libusb_handle_events_completed(libusb_context *ctx, int *completed); -int LIBUSB_CALL libusb_handle_events_locked(libusb_context *ctx, - struct timeval *tv); -int LIBUSB_CALL libusb_pollfds_handle_timeouts(libusb_context *ctx); -int LIBUSB_CALL libusb_get_next_timeout(libusb_context *ctx, - struct timeval *tv); - -/** \ingroup poll - * File descriptor for polling - */ -struct libusb_pollfd { - /** Numeric file descriptor */ - int fd; - - /** Event flags to poll for from <poll.h>. POLLIN indicates that you - * should monitor this file descriptor for becoming ready to read from, - * and POLLOUT indicates that you should monitor this file descriptor for - * nonblocking write readiness. */ - short events; -}; - -/** \ingroup poll - * Callback function, invoked when a new file descriptor should be added - * to the set of file descriptors monitored for events. - * \param fd the new file descriptor - * \param events events to monitor for, see \ref libusb_pollfd for a - * description - * \param user_data User data pointer specified in - * libusb_set_pollfd_notifiers() call - * \see libusb_set_pollfd_notifiers() - */ -typedef void (LIBUSB_CALL *libusb_pollfd_added_cb)(int fd, short events, - void *user_data); - -/** \ingroup poll - * Callback function, invoked when a file descriptor should be removed from - * the set of file descriptors being monitored for events. After returning - * from this callback, do not use that file descriptor again. - * \param fd the file descriptor to stop monitoring - * \param user_data User data pointer specified in - * libusb_set_pollfd_notifiers() call - * \see libusb_set_pollfd_notifiers() - */ -typedef void (LIBUSB_CALL *libusb_pollfd_removed_cb)(int fd, void *user_data); - -const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds( - libusb_context *ctx); -void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx, - libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, - void *user_data); - -/** \ingroup hotplug - * Callback handle. - * - * Callbacks handles are generated by libusb_hotplug_register_callback() - * and can be used to deregister callbacks. Callback handles are unique - * per libusb_context and it is safe to call libusb_hotplug_deregister_callback() - * on an already deregisted callback. - * - * Since version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102 - * - * For more information, see \ref hotplug. - */ -typedef int libusb_hotplug_callback_handle; - -/** \ingroup hotplug - * - * Since version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102 - * - * Flags for hotplug events */ -typedef enum { - /** Arm the callback and fire it for all matching currently attached devices. */ - LIBUSB_HOTPLUG_ENUMERATE = 1, -} libusb_hotplug_flag; - -/** \ingroup hotplug - * - * Since version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102 - * - * Hotplug events */ -typedef enum { - /** A device has been plugged in and is ready to use */ - LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = 0x01, - - /** A device has left and is no longer available. - * It is the user's responsibility to call libusb_close on any handle associated with a disconnected device. - * It is safe to call libusb_get_device_descriptor on a device that has left */ - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = 0x02, -} libusb_hotplug_event; - -/** \ingroup hotplug - * Wildcard matching for hotplug events */ -#define LIBUSB_HOTPLUG_MATCH_ANY -1 - -/** \ingroup hotplug - * Hotplug callback function type. When requesting hotplug event notifications, - * you pass a pointer to a callback function of this type. - * - * This callback may be called by an internal event thread and as such it is - * recommended the callback do minimal processing before returning. - * - * libusbx will call this function later, when a matching event had happened on - * a matching device. See \ref hotplug for more information. - * - * It is safe to call either libusb_hotplug_register_callback() or - * libusb_hotplug_deregister_callback() from within a callback function. - * - * Since version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102 - * - * \param libusb_context context of this notification - * \param device libusb_device this event occurred on - * \param event event that occurred - * \param user_data user data provided when this callback was registered - * \returns bool whether this callback is finished processing events. - * returning 1 will cause this callback to be deregistered - */ -typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx, - libusb_device *device, - libusb_hotplug_event event, - void *user_data); - -/** \ingroup hotplug - * Register a hotplug callback function - * - * Register a callback with the libusb_context. The callback will fire - * when a matching event occurs on a matching device. The callback is - * armed until either it is deregistered with libusb_hotplug_deregister_callback() - * or the supplied callback returns 1 to indicate it is finished processing events. - * - * Since version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102 - * - * \param[in] ctx context to register this callback with - * \param[in] events bitwise or of events that will trigger this callback. See \ref - * libusb_hotplug_event - * \param[in] flags hotplug callback flags. See \ref libusb_hotplug_flag - * \param[in] vendor_id the vendor id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY - * \param[in] product_id the product id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY - * \param[in] dev_class the device class to match or \ref LIBUSB_HOTPLUG_MATCH_ANY - * \param[in] cb_fn the function to be invoked on a matching event/device - * \param[in] user_data user data to pass to the callback function - * \param[out] handle pointer to store the handle of the allocated callback (can be NULL) - * \returns LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure - */ -int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx, - libusb_hotplug_event events, - libusb_hotplug_flag flags, - int vendor_id, int product_id, - int dev_class, - libusb_hotplug_callback_fn cb_fn, - void *user_data, - libusb_hotplug_callback_handle *handle); - -/** \ingroup hotplug - * Deregisters a hotplug callback. - * - * Deregister a callback from a libusb_context. This function is safe to call from within - * a hotplug callback. - * - * Since version 1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102 - * - * \param[in] ctx context this callback is registered with - * \param[in] handle the handle of the callback to deregister - */ -void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx, - libusb_hotplug_callback_handle handle); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/libusbi.h b/src/3rd_party-static/libusbx-1.0.16/libusb/libusbi.h deleted file mode 100644 index 02efae300d..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/libusbi.h +++ /dev/null @@ -1,1004 +0,0 @@ -/* - * 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 - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LIBUSBI_H -#define LIBUSBI_H - -#include "config.h" - -#include <stddef.h> -#include <stdint.h> -#include <time.h> -#include <stdarg.h> -#ifdef HAVE_POLL_H -#include <poll.h> -#endif - -#ifdef HAVE_MISSING_H -#include "missing.h" -#endif -#include "libusb.h" -#include "version.h" - -/* Inside the libusbx code, mark all public functions as follows: - * return_type API_EXPORTED function_name(params) { ... } - * But if the function returns a pointer, mark it as follows: - * DEFAULT_VISIBILITY return_type * LIBUSB_CALL function_name(params) { ... } - * In the libusbx public header, mark all declarations as: - * return_type LIBUSB_CALL function_name(params); - */ -#define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY - -#define DEVICE_DESC_LENGTH 18 - -#define USB_MAXENDPOINTS 32 -#define USB_MAXINTERFACES 32 -#define USB_MAXCONFIG 8 - -/* 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 *prev, *next; -}; - -/* Get an entry from the list - * ptr - the address of this list_head element in "type" - * type - the data type that contains "member" - * member - the list_head element in "type" - */ -#define list_entry(ptr, type, member) \ - ((type *)((uintptr_t)(ptr) - (uintptr_t)offsetof(type, member))) - -/* Get each entry from a list - * pos - A structure pointer has a "member" element - * head - list head - * member - the list_head element in "pos" - * type - the type of the first parameter - */ -#define list_for_each_entry(pos, head, member, type) \ - for (pos = list_entry((head)->next, type, member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, type, member)) - -#define list_for_each_entry_safe(pos, n, head, member, type) \ - for (pos = list_entry((head)->next, type, member), \ - n = list_entry(pos->member.next, type, member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, type, member)) - -#define list_empty(entry) ((entry)->next == (entry)) - -static inline void list_init(struct list_head *entry) -{ - entry->prev = entry->next = entry; -} - -static inline void list_add(struct list_head *entry, struct list_head *head) -{ - entry->next = head->next; - entry->prev = head; - - head->next->prev = entry; - head->next = entry; -} - -static inline void list_add_tail(struct list_head *entry, - struct list_head *head) -{ - entry->next = head; - entry->prev = head->prev; - - head->prev->next = entry; - head->prev = entry; -} - -static inline void list_del(struct list_head *entry) -{ - entry->next->prev = entry->prev; - entry->prev->next = entry->next; - 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) ({ \ - const typeof( ((type *)0)->member ) *mptr = (ptr); \ - (type *)( (char *)mptr - offsetof(type,member) );}) - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -#define TIMESPEC_IS_SET(ts) ((ts)->tv_sec != 0 || (ts)->tv_nsec != 0) - -void usbi_log(struct libusb_context *ctx, enum libusb_log_level level, - const char *function, const char *format, ...); - -void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level, - const char *function, const char *format, va_list args); - -#if !defined(_MSC_VER) || _MSC_VER >= 1400 - -#ifdef ENABLE_LOGGING -#define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__) -#define usbi_dbg(...) _usbi_log(NULL, LIBUSB_LOG_LEVEL_DEBUG, __VA_ARGS__) -#else -#define _usbi_log(ctx, level, ...) do { (void)(ctx); } while(0) -#define usbi_dbg(...) do {} while(0) -#endif - -#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 */ - -#ifdef ENABLE_LOGGING -#define LOG_BODY(ctxt, level) \ -{ \ - va_list args; \ - va_start (args, format); \ - usbi_log_v(ctxt, level, "", format, args); \ - va_end(args); \ -} -#else -#define LOG_BODY(ctxt, level) do { (void)(ctxt); } while(0) -#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 *format, ...) - LOG_BODY(NULL,LIBUSB_LOG_LEVEL_DEBUG) - -#endif /* !defined(_MSC_VER) || _MSC_VER >= 1400 */ - -#define USBI_GET_CONTEXT(ctx) if (!(ctx)) (ctx) = usbi_default_context -#define DEVICE_CTX(dev) ((dev)->ctx) -#define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev)) -#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle)) -#define ITRANSFER_CTX(transfer) \ - (TRANSFER_CTX(USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer))) - -#define IS_EPIN(ep) (0 != ((ep) & LIBUSB_ENDPOINT_IN)) -#define IS_EPOUT(ep) (!IS_EPIN(ep)) -#define IS_XFERIN(xfer) (0 != ((xfer)->endpoint & LIBUSB_ENDPOINT_IN)) -#define IS_XFEROUT(xfer) (!IS_XFERIN(xfer)) - -/* Internal abstraction for thread synchronization */ -#if defined(THREADS_POSIX) -#include "os/threads_posix.h" -#elif defined(OS_WINDOWS) || defined(OS_WINCE) -#include <os/threads_windows.h> -#endif - -extern struct libusb_context *usbi_default_context; - -struct libusb_context { - int debug; - int debug_fixed; - - /* internal control pipe, used for interrupting event handling when - * something needs to modify poll fds. */ - int ctrl_pipe[2]; - - struct list_head usb_devs; - usbi_mutex_t usb_devs_lock; - - /* A list of open handles. Backends are free to traverse this if required. - */ - struct list_head open_devs; - usbi_mutex_t open_devs_lock; - - /* A list of registered hotplug callbacks */ - struct list_head hotplug_cbs; - usbi_mutex_t hotplug_cbs_lock; - int hotplug_pipe[2]; - - /* this is a list of in-flight transfer handles, sorted by timeout - * expiration. URBs to timeout the soonest are placed at the beginning of - * the list, URBs that will time out later are placed after, and urbs with - * infinite timeout are always placed at the very end. */ - struct list_head flying_transfers; - usbi_mutex_t flying_transfers_lock; - - /* list of poll fds */ - struct list_head pollfds; - usbi_mutex_t pollfds_lock; - - /* a counter that is set when we want to interrupt event handling, in order - * to modify the poll fd set. and a lock to protect it. */ - unsigned int pollfd_modify; - usbi_mutex_t pollfd_modify_lock; - - /* user callbacks for pollfd changes */ - libusb_pollfd_added_cb fd_added_cb; - libusb_pollfd_removed_cb fd_removed_cb; - void *fd_cb_user_data; - - /* ensures that only one thread is handling events at any one time */ - usbi_mutex_t events_lock; - - /* used to see if there is an active thread doing event handling */ - int event_handler_active; - - /* used to wait for event completion in threads other than the one that is - * event handling */ - usbi_mutex_t event_waiters_lock; - usbi_cond_t event_waiters_cond; - -#ifdef USBI_TIMERFD_AVAILABLE - /* used for timeout handling, if supported by OS. - * this timerfd is maintained to trigger on the next pending timeout */ - int timerfd; -#endif - - struct list_head list; -}; - -#ifdef USBI_TIMERFD_AVAILABLE -#define usbi_using_timerfd(ctx) ((ctx)->timerfd >= 0) -#else -#define usbi_using_timerfd(ctx) (0) -#endif - -struct libusb_device { - /* lock protects refcnt, everything else is finalized at initialization - * time */ - usbi_mutex_t lock; - int refcnt; - - struct libusb_context *ctx; - - uint8_t bus_number; - uint8_t port_number; - struct libusb_device* parent_dev; - uint8_t device_address; - uint8_t num_configurations; - enum libusb_speed speed; - - struct list_head list; - unsigned long session_data; - - struct libusb_device_descriptor device_descriptor; - int attached; - - unsigned char os_priv -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif - ; -}; - -struct libusb_device_handle { - /* lock protects claimed_interfaces */ - usbi_mutex_t lock; - unsigned long claimed_interfaces; - - struct list_head list; - struct libusb_device *dev; - int auto_detach_kernel_driver; - unsigned char os_priv -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif - ; -}; - -enum { - USBI_CLOCK_MONOTONIC, - USBI_CLOCK_REALTIME -}; - -/* in-memory transfer layout: - * - * 1. struct usbi_transfer - * 2. struct libusb_transfer (which includes iso packets) [variable size] - * 3. os private data [variable size] - * - * from a libusb_transfer, you can get the usbi_transfer by rewinding the - * appropriate number of bytes. - * the usbi_transfer includes the number of allocated packets, so you can - * determine the size of the transfer and hence the start and length of the - * OS-private data. - */ - -struct usbi_transfer { - int num_iso_packets; - struct list_head list; - struct timeval timeout; - int transferred; - uint8_t flags; - - /* this lock is held during libusb_submit_transfer() and - * libusb_cancel_transfer() (allowing the OS backend to prevent duplicate - * cancellation, submission-during-cancellation, etc). the OS backend - * should also take this lock in the handle_events path, to prevent the user - * cancelling the transfer from another thread while you are processing - * its completion (presumably there would be races within your OS backend - * if this were possible). */ - usbi_mutex_t lock; -}; - -enum usbi_transfer_flags { - /* The transfer has timed out */ - USBI_TRANSFER_TIMED_OUT = 1 << 0, - - /* Set by backend submit_transfer() if the OS handles timeout */ - USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 1, - - /* Cancellation was requested via libusb_cancel_transfer() */ - USBI_TRANSFER_CANCELLING = 1 << 2, - - /* Operation on the transfer failed because the device disappeared */ - USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3, - - /* Set by backend submit_transfer() if the fds in use have been updated */ - USBI_TRANSFER_UPDATED_FDS = 1 << 4, -}; - -#define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \ - ((struct libusb_transfer *)(((unsigned char *)(transfer)) \ - + sizeof(struct usbi_transfer))) -#define LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer) \ - ((struct usbi_transfer *)(((unsigned char *)(transfer)) \ - - sizeof(struct usbi_transfer))) - -static inline void *usbi_transfer_get_os_priv(struct usbi_transfer *transfer) -{ - return ((unsigned char *)transfer) + sizeof(struct usbi_transfer) - + sizeof(struct libusb_transfer) - + (transfer->num_iso_packets - * sizeof(struct libusb_iso_packet_descriptor)); -} - -/* bus structures */ - -/* All standard descriptors have these 2 fields in common */ -struct usb_descriptor_header { - uint8_t bLength; - uint8_t bDescriptorType; -}; - -/* shared data and functions */ - -int usbi_io_init(struct libusb_context *ctx); -void usbi_io_exit(struct libusb_context *ctx); - -struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, - unsigned long session_id); -struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx, - unsigned long session_id); -int usbi_sanitize_device(struct libusb_device *dev); -void usbi_handle_disconnect(struct libusb_device_handle *handle); - -int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, - enum libusb_transfer_status status); -int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer); - -int usbi_parse_descriptor(const unsigned char *source, const char *descriptor, - void *dest, int host_endian); -int usbi_device_cache_descriptor(libusb_device *dev); -int usbi_get_config_index_by_value(struct libusb_device *dev, - uint8_t bConfigurationValue, int *idx); - -void usbi_connect_device (struct libusb_device *dev); -void usbi_disconnect_device (struct libusb_device *dev); - -/* Internal abstraction for poll (needs struct usbi_transfer on Windows) */ -#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) -#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 { - /* must come first */ - struct libusb_pollfd pollfd; - - struct list_head list; -}; - -int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events); -void usbi_remove_pollfd(struct libusb_context *ctx, int fd); -void usbi_fd_notification(struct libusb_context *ctx); - -/* device discovery */ - -/* we traverse usbfs without knowing how many devices we are going to find. - * so we create this discovered_devs model which is similar to a linked-list - * which grows when required. it can be freed once discovery has completed, - * eliminating the need for a list node in the libusb_device structure - * itself. */ -struct discovered_devs { - size_t len; - size_t capacity; - struct libusb_device *devices -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif - ; -}; - -struct discovered_devs *discovered_devs_append( - struct discovered_devs *discdevs, struct libusb_device *dev); - -/* OS abstraction */ - -/* This is the interface that OS backends need to implement. - * All fields are mandatory, except ones explicitly noted as optional. */ -struct usbi_os_backend { - /* A human-readable name for your backend, e.g. "Linux usbfs" */ - const char *name; - - /* Binary mask for backend specific capabilities */ - uint32_t caps; - - /* Perform initialization of your backend. You might use this function - * to determine specific capabilities of the system, allocate required - * data structures for later, etc. - * - * This function is called when a libusbx user initializes the library - * prior to use. - * - * Return 0 on success, or a LIBUSB_ERROR code on failure. - */ - int (*init)(struct libusb_context *ctx); - - /* Deinitialization. Optional. This function should destroy anything - * that was set up by init. - * - * This function is called when the user deinitializes the library. - */ - void (*exit)(void); - - /* Enumerate all the USB devices on the system, returning them in a list - * of discovered devices. - * - * Your implementation should enumerate all devices on the system, - * regardless of whether they have been seen before or not. - * - * When you have found a device, compute a session ID for it. The session - * ID should uniquely represent that particular device for that particular - * connection session since boot (i.e. if you disconnect and reconnect a - * device immediately after, it should be assigned a different session ID). - * If your OS cannot provide a unique session ID as described above, - * presenting a session ID of (bus_number << 8 | device_address) should - * be sufficient. Bus numbers and device addresses wrap and get reused, - * but that is an unlikely case. - * - * After computing a session ID for a device, call - * usbi_get_device_by_session_id(). This function checks if libusbx already - * knows about the device, and if so, it provides you with a libusb_device - * structure for it. - * - * If usbi_get_device_by_session_id() returns NULL, it is time to allocate - * a new device structure for the device. Call usbi_alloc_device() to - * obtain a new libusb_device structure with reference count 1. Populate - * the bus_number and device_address attributes of the new device, and - * perform any other internal backend initialization you need to do. At - * this point, you should be ready to provide device descriptors and so - * on through the get_*_descriptor functions. Finally, call - * usbi_sanitize_device() to perform some final sanity checks on the - * device. Assuming all of the above succeeded, we can now continue. - * If any of the above failed, remember to unreference the device that - * was returned by usbi_alloc_device(). - * - * At this stage we have a populated libusb_device structure (either one - * that was found earlier, or one that we have just allocated and - * populated). This can now be added to the discovered devices list - * using discovered_devs_append(). Note that discovered_devs_append() - * may reallocate the list, returning a new location for it, and also - * note that reallocation can fail. Your backend should handle these - * error conditions appropriately. - * - * This function should not generate any bus I/O and should not block. - * If I/O is required (e.g. reading the active configuration value), it is - * OK to ignore these suggestions :) - * - * This function is executed when the user wishes to retrieve a list - * of USB devices connected to the system. - * - * If the backend has hotplug support, this function is not used! - * - * Return 0 on success, or a LIBUSB_ERROR code on failure. - */ - int (*get_device_list)(struct libusb_context *ctx, - 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 - * is preallocated for you, you can retrieve the device in question - * through handle->dev. - * - * Your backend should allocate any internal resources required for I/O - * and other operations so that those operations can happen (hopefully) - * without hiccup. This is also a good place to inform libusbx that it - * should monitor certain file descriptors related to this device - - * see the usbi_add_pollfd() function. - * - * This function should not generate any bus I/O and should not block. - * - * This function is called when the user attempts to obtain a device - * handle for a device. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_ACCESS if the user has insufficient permissions - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since - * discovery - * - another LIBUSB_ERROR code on other failure - * - * Do not worry about freeing the handle on failed open, the upper layers - * do this for you. - */ - int (*open)(struct libusb_device_handle *handle); - - /* Close a device such that the handle cannot be used again. Your backend - * should destroy any resources that were allocated in the open path. - * This may also be a good place to call usbi_remove_pollfd() to inform - * libusbx of any file descriptors associated with this device that should - * no longer be monitored. - * - * This function is called when the user closes a device handle. - */ - void (*close)(struct libusb_device_handle *handle); - - /* Retrieve the device descriptor from a device. - * - * The descriptor should be retrieved from memory, NOT via bus I/O to the - * device. This means that you may have to cache it in a private structure - * during get_device_list enumeration. Alternatively, you may be able - * to retrieve it from a kernel interface (some Linux setups can do this) - * still without generating bus I/O. - * - * This function is expected to write DEVICE_DESC_LENGTH (18) bytes into - * buffer, which is guaranteed to be big enough. - * - * This function is called when sanity-checking a device before adding - * it to the list of discovered devices, and also when the user requests - * to read the device descriptor. - * - * This function is expected to return the descriptor in bus-endian format - * (LE). If it returns the multi-byte values in host-endian format, - * set the host_endian output parameter to "1". - * - * Return 0 on success or a LIBUSB_ERROR code on failure. - */ - int (*get_device_descriptor)(struct libusb_device *device, - unsigned char *buffer, int *host_endian); - - /* Get the ACTIVE configuration descriptor for a device. - * - * The descriptor should be retrieved from memory, NOT via bus I/O to the - * device. This means that you may have to cache it in a private structure - * during get_device_list enumeration. You may also have to keep track - * of which configuration is active when the user changes it. - * - * This function is expected to write len bytes of data into buffer, which - * is guaranteed to be big enough. If you can only do a partial write, - * return an error code. - * - * This function is expected to return the descriptor in bus-endian format - * (LE). If it returns the multi-byte values in host-endian format, - * set the host_endian output parameter to "1". - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state - * - another LIBUSB_ERROR code on other failure - */ - int (*get_active_config_descriptor)(struct libusb_device *device, - unsigned char *buffer, size_t len, int *host_endian); - - /* Get a specific configuration descriptor for a device. - * - * The descriptor should be retrieved from memory, NOT via bus I/O to the - * device. This means that you may have to cache it in a private structure - * during get_device_list enumeration. - * - * The requested descriptor is expressed as a zero-based index (i.e. 0 - * indicates that we are requesting the first descriptor). The index does - * not (necessarily) equal the bConfigurationValue of the configuration - * being requested. - * - * This function is expected to write len bytes of data into buffer, which - * is guaranteed to be big enough. If you can only do a partial write, - * return an error code. - * - * This function is expected to return the descriptor in bus-endian format - * (LE). If it returns the multi-byte values in host-endian format, - * set the host_endian output parameter to "1". - * - * Return 0 on success or a LIBUSB_ERROR code on failure. - */ - int (*get_config_descriptor)(struct libusb_device *device, - uint8_t config_index, unsigned char *buffer, size_t len, - int *host_endian); - - /* 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. - * Optional. This should only be implemented if you can retrieve it from - * cache (don't generate I/O). - * - * If you cannot retrieve this from cache, either do not implement this - * function, or return LIBUSB_ERROR_NOT_SUPPORTED. This will cause - * libusbx to retrieve the information through a standard control transfer. - * - * This function must be non-blocking. - * Return: - * - 0 on success - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - LIBUSB_ERROR_NOT_SUPPORTED if the value cannot be retrieved without - * blocking - * - another LIBUSB_ERROR code on other failure. - */ - int (*get_configuration)(struct libusb_device_handle *handle, int *config); - - /* Set the active configuration for a device. - * - * A configuration value of -1 should put the device in unconfigured state. - * - * This function can block. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the configuration does not exist - * - LIBUSB_ERROR_BUSY if interfaces are currently claimed (and hence - * configuration cannot be changed) - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure. - */ - int (*set_configuration)(struct libusb_device_handle *handle, int config); - - /* Claim an interface. When claimed, the application can then perform - * I/O to an interface's endpoints. - * - * This function should not generate any bus I/O and should not block. - * Interface claiming is a logical operation that simply ensures that - * no other drivers/applications are using the interface, and after - * claiming, no other drivers/applicatiosn can use the interface because - * we now "own" it. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the interface does not exist - * - LIBUSB_ERROR_BUSY if the interface is in use by another driver/app - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*claim_interface)(struct libusb_device_handle *handle, int interface_number); - - /* Release a previously claimed interface. - * - * This function should also generate a SET_INTERFACE control request, - * resetting the alternate setting of that interface to 0. It's OK for - * this function to block as a result. - * - * You will only ever be asked to release an interface which was - * successfully claimed earlier. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*release_interface)(struct libusb_device_handle *handle, int interface_number); - - /* Set the alternate setting for an interface. - * - * You will only ever be asked to set the alternate setting for an - * interface which was successfully claimed earlier. - * - * It's OK for this function to block. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the alternate setting does not exist - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*set_interface_altsetting)(struct libusb_device_handle *handle, - int interface_number, int altsetting); - - /* Clear a halt/stall condition on an endpoint. - * - * It's OK for this function to block. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*clear_halt)(struct libusb_device_handle *handle, - unsigned char endpoint); - - /* Perform a USB port reset to reinitialize a device. - * - * If possible, the handle should still be usable after the reset - * completes, assuming that the device descriptors did not change during - * reset and all previous interface state can be restored. - * - * If something changes, or you cannot easily locate/verify the resetted - * device, return LIBUSB_ERROR_NOT_FOUND. This prompts the application - * to close the old handle and re-enumerate the device. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the device - * has been disconnected since it was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*reset_device)(struct libusb_device_handle *handle); - - /* Determine if a kernel driver is active on an interface. Optional. - * - * The presence of a kernel driver on an interface indicates that any - * calls to claim_interface would fail with the LIBUSB_ERROR_BUSY code. - * - * Return: - * - 0 if no driver is active - * - 1 if a driver is active - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*kernel_driver_active)(struct libusb_device_handle *handle, - int interface_number); - - /* Detach a kernel driver from an interface. Optional. - * - * After detaching a kernel driver, the interface should be available - * for claim. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*detach_kernel_driver)(struct libusb_device_handle *handle, - int interface_number); - - /* Attach a kernel driver to an interface. Optional. - * - * Reattach a kernel driver to the device. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - LIBUSB_ERROR_BUSY if a program or driver has claimed the interface, - * preventing reattachment - * - another LIBUSB_ERROR code on other failure - */ - int (*attach_kernel_driver)(struct libusb_device_handle *handle, - int interface_number); - - /* Destroy a device. Optional. - * - * This function is called when the last reference to a device is - * destroyed. It should free any resources allocated in the get_device_list - * path. - */ - void (*destroy_device)(struct libusb_device *dev); - - /* Submit a transfer. Your implementation should take the transfer, - * morph it into whatever form your platform requires, and submit it - * asynchronously. - * - * This function must not block. - * - * This function gets called with the flying_transfers_lock locked! - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * - another LIBUSB_ERROR code on other failure - */ - int (*submit_transfer)(struct usbi_transfer *itransfer); - - /* Cancel a previously submitted transfer. - * - * This function must not block. The transfer cancellation must complete - * later, resulting in a call to usbi_handle_transfer_cancellation() - * from the context of handle_events. - */ - int (*cancel_transfer)(struct usbi_transfer *itransfer); - - /* Clear a transfer as if it has completed or cancelled, but do not - * report any completion/cancellation to the library. You should free - * all private data from the transfer as if you were just about to report - * completion or cancellation. - * - * This function might seem a bit out of place. It is used when libusbx - * detects a disconnected device - it calls this function for all pending - * transfers before reporting completion (with the disconnect code) to - * the user. Maybe we can improve upon this internal interface in future. - */ - void (*clear_transfer_priv)(struct usbi_transfer *itransfer); - - /* Handle any pending events. This involves monitoring any active - * transfers and processing their completion or cancellation. - * - * The function is passed an array of pollfd structures (size nfds) - * as a result of the poll() system call. The num_ready parameter - * indicates the number of file descriptors that have reported events - * (i.e. the poll() return value). This should be enough information - * for you to determine which actions need to be taken on the currently - * active transfers. - * - * For any cancelled transfers, call usbi_handle_transfer_cancellation(). - * For completed transfers, call usbi_handle_transfer_completion(). - * For control/bulk/interrupt transfers, populate the "transferred" - * element of the appropriate usbi_transfer structure before calling the - * above functions. For isochronous transfers, populate the status and - * transferred fields of the iso packet descriptors of the transfer. - * - * This function should also be able to detect disconnection of the - * device, reporting that situation with usbi_handle_disconnect(). - * - * When processing an event related to a transfer, you probably want to - * take usbi_transfer.lock to prevent races. See the documentation for - * the usbi_transfer structure. - * - * Return 0 on success, or a LIBUSB_ERROR code on failure. - */ - int (*handle_events)(struct libusb_context *ctx, - struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready); - - /* Get time from specified clock. At least two clocks must be implemented - by the backend: USBI_CLOCK_REALTIME, and USBI_CLOCK_MONOTONIC. - - Description of clocks: - USBI_CLOCK_REALTIME : clock returns time since system epoch. - USBI_CLOCK_MONOTONIC: clock returns time since unspecified start - time (usually boot). - */ - int (*clock_gettime)(int clkid, struct timespec *tp); - -#ifdef USBI_TIMERFD_AVAILABLE - /* clock ID of the clock that should be used for timerfd */ - clockid_t (*get_timerfd_clockid)(void); -#endif - - /* Number of bytes to reserve for per-device private backend data. - * This private data area is accessible through the "os_priv" field of - * struct libusb_device. */ - size_t device_priv_size; - - /* Number of bytes to reserve for per-handle private backend data. - * This private data area is accessible through the "os_priv" field of - * struct libusb_device. */ - size_t device_handle_priv_size; - - /* Number of bytes to reserve for per-transfer private backend data. - * This private data area is accessible by calling - * usbi_transfer_get_os_priv() on the appropriate usbi_transfer instance. - */ - size_t transfer_priv_size; - - /* Mumber of additional bytes for os_priv for each iso packet. - * Can your backend use this? */ - /* FIXME: linux can't use this any more. if other OS's cannot either, - * then remove this */ - size_t add_iso_packet_size; -}; - -extern const struct usbi_os_backend * const usbi_backend; - -extern const struct usbi_os_backend linux_usbfs_backend; -extern const struct usbi_os_backend darwin_backend; -extern const struct usbi_os_backend openbsd_backend; -extern const struct usbi_os_backend windows_backend; -extern const struct usbi_os_backend wince_backend; - -extern struct list_head active_contexts_list; -extern usbi_mutex_static_t active_contexts_lock; - -#endif diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/darwin_usb.c b/src/3rd_party-static/libusbx-1.0.16/libusb/os/darwin_usb.c deleted file mode 100644 index a24558cb59..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/darwin_usb.c +++ /dev/null @@ -1,1903 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode:nil -*- */ -/* - * 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 - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include <ctype.h> -#include <errno.h> -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <unistd.h> -#include <fcntl.h> -#include <libkern/OSAtomic.h> - -#include <mach/clock.h> -#include <mach/clock_types.h> -#include <mach/mach_host.h> -#include <mach/mach_port.h> - -#include <AvailabilityMacros.h> -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 - #include <objc/objc-auto.h> -#endif - -#include "darwin_usb.h" - -/* async event thread */ -static pthread_mutex_t libusb_darwin_at_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t libusb_darwin_at_cond = PTHREAD_COND_INITIALIZER; - -static clock_serv_t clock_realtime; -static clock_serv_t clock_monotonic; - -static CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */ -static volatile int32_t initCount = 0; - -static usbi_mutex_t darwin_cached_devices_lock = PTHREAD_MUTEX_INITIALIZER; -static struct list_head darwin_cached_devices = {&darwin_cached_devices, &darwin_cached_devices}; - -#define DARWIN_CACHED_DEVICE(a) ((struct darwin_cached_device *) (((struct darwin_device_priv *)((a)->os_priv))->dev)) - -/* async event thread */ -static pthread_t libusb_darwin_at; - -static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian); -static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface); -static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface); -static int darwin_reset_device(struct libusb_device_handle *dev_handle); -static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0); - -static int darwin_scan_devices(struct libusb_context *ctx); -static int process_new_device (struct libusb_context *ctx, io_service_t service); - -#if defined(ENABLE_LOGGING) -static const char *darwin_error_str (int result) { - switch (result) { - case kIOReturnSuccess: - return "no error"; - case kIOReturnNotOpen: - return "device not opened for exclusive access"; - case kIOReturnNoDevice: - return "no connection to an IOService"; - case kIOUSBNoAsyncPortErr: - return "no async port has been opened for interface"; - case kIOReturnExclusiveAccess: - return "another process has device opened for exclusive access"; - case kIOUSBPipeStalled: - return "pipe is stalled"; - case kIOReturnError: - return "could not establish a connection to the Darwin kernel"; - case kIOUSBTransactionTimeout: - return "transaction timed out"; - case kIOReturnBadArgument: - return "invalid argument"; - case kIOReturnAborted: - return "transaction aborted"; - case kIOReturnNotResponding: - return "device not responding"; - case kIOReturnOverrun: - return "data overrun"; - case kIOReturnCannotWire: - return "physical memory can not be wired down"; - case kIOReturnNoResources: - return "out of resources"; - case kIOUSBHighSpeedSplitError: - return "high speed split error"; - default: - return "unknown error"; - } -} -#endif - -static int darwin_to_libusb (int result) { - switch (result) { - case kIOReturnUnderrun: - case kIOReturnSuccess: - return LIBUSB_SUCCESS; - case kIOReturnNotOpen: - case kIOReturnNoDevice: - return LIBUSB_ERROR_NO_DEVICE; - case kIOReturnExclusiveAccess: - return LIBUSB_ERROR_ACCESS; - case kIOUSBPipeStalled: - return LIBUSB_ERROR_PIPE; - case kIOReturnBadArgument: - return LIBUSB_ERROR_INVALID_PARAM; - case kIOUSBTransactionTimeout: - return LIBUSB_ERROR_TIMEOUT; - case kIOReturnNotResponding: - case kIOReturnAborted: - case kIOReturnError: - case kIOUSBNoAsyncPortErr: - default: - return LIBUSB_ERROR_OTHER; - } -} - -/* this function must be called with the darwin_cached_devices_lock held */ -static void darwin_deref_cached_device(struct darwin_cached_device *cached_dev) { - cached_dev->refcount--; - /* free the device and remove it from the cache */ - if (0 == cached_dev->refcount) { - list_del(&cached_dev->list); - - (*(cached_dev->device))->Release(cached_dev->device); - free (cached_dev); - } -} - -static void darwin_ref_cached_device(struct darwin_cached_device *cached_dev) { - cached_dev->refcount++; -} - -static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, uint8_t *pipep, uint8_t *ifcp) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - - /* current interface */ - struct darwin_interface *cInterface; - - int8_t i, iface; - - usbi_dbg ("converting ep address 0x%02x to pipeRef and interface", ep); - - for (iface = 0 ; iface < USB_MAXINTERFACES ; iface++) { - cInterface = &priv->interfaces[iface]; - - if (dev_handle->claimed_interfaces & (1 << iface)) { - for (i = 0 ; i < cInterface->num_endpoints ; i++) { - if (cInterface->endpoint_addrs[i] == ep) { - *pipep = i + 1; - *ifcp = iface; - usbi_dbg ("pipe %d on interface %d matches", *pipep, *ifcp); - return 0; - } - } - } - } - - /* No pipe found with the correct endpoint address */ - usbi_warn (HANDLE_CTX(dev_handle), "no pipeRef found with endpoint address 0x%02x.", ep); - - return -1; -} - -static int usb_setup_device_iterator (io_iterator_t *deviceIterator, UInt32 location) { - CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName); - - if (!matchingDict) - return kIOReturnError; - - if (location) { - CFMutableDictionaryRef propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - if (propertyMatchDict) { - /* there are no unsigned CFNumber types so treat the value as signed. the os seems to do this - internally (CFNumberType of locationID is 3) */ - CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberSInt32Type, &location); - - CFDictionarySetValue (propertyMatchDict, CFSTR(kUSBDevicePropertyLocationID), locationCF); - /* release our reference to the CFNumber (CFDictionarySetValue retains it) */ - CFRelease (locationCF); - - CFDictionarySetValue (matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict); - /* release out reference to the CFMutableDictionaryRef (CFDictionarySetValue retains it) */ - CFRelease (propertyMatchDict); - } - /* else we can still proceed as long as the caller accounts for the possibility of other devices in the iterator */ - } - - return IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, deviceIterator); -} - -static int get_ioregistry_value_number (io_service_t service, CFStringRef property, CFNumberType type, void *p) { - CFTypeRef cfNumber = IORegistryEntryCreateCFProperty (service, property, kCFAllocatorDefault, 0); - int ret = 0; - - if (cfNumber) { - if (CFGetTypeID(cfNumber) == CFNumberGetTypeID()) { - ret = CFNumberGetValue(cfNumber, type, p); - } - - CFRelease (cfNumber); - } - - return ret; -} - -static usb_device_t **darwin_device_from_service (io_service_t service) -{ - io_cf_plugin_ref_t *plugInInterface = NULL; - usb_device_t **device; - kern_return_t result; - SInt32 score; - - result = IOCreatePlugInInterfaceForService(service, kIOUSBDeviceUserClientTypeID, - kIOCFPlugInInterfaceID, &plugInInterface, - &score); - - if (kIOReturnSuccess != result || !plugInInterface) { - usbi_dbg ("could not set up plugin for service: %s\n", darwin_error_str (result)); - return NULL; - } - - (void)(*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID), - (LPVOID)&device); - /* Use release instead of IODestroyPlugInInterface to avoid stopping IOServices associated with this device */ - (*plugInInterface)->Release (plugInInterface); - - return device; -} - -static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) { - struct libusb_context *ctx; - io_service_t service; - - usbi_mutex_lock(&active_contexts_lock); - - while ((service = IOIteratorNext(add_devices))) { - /* add this device to each active context's device list */ - list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) { - process_new_device (ctx, service);; - } - - IOObjectRelease(service); - } - - usbi_mutex_unlock(&active_contexts_lock); -} - -static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) { - struct libusb_device *dev = NULL; - struct libusb_context *ctx; - - io_service_t device; - UInt64 session; - int ret; - - while ((device = IOIteratorNext (rem_devices)) != 0) { - /* get the location from the i/o registry */ - ret = get_ioregistry_value_number (device, CFSTR("sessionID"), kCFNumberSInt64Type, &session); - IOObjectRelease (device); - if (!ret) - continue; - - usbi_mutex_lock(&active_contexts_lock); - - list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) { - usbi_dbg ("notifying context %p of device disconnect", ctx); - - dev = usbi_get_device_by_session_id(ctx, session); - if (dev) { - /* signal the core that this device has been disconnected. the core will tear down this device - when the reference count reaches 0 */ - usbi_disconnect_device(dev); - } - } - - usbi_mutex_unlock(&active_contexts_lock); - } -} - -static void darwin_clear_iterator (io_iterator_t iter) { - io_service_t device; - - while ((device = IOIteratorNext (iter)) != 0) - IOObjectRelease (device); -} - -static void *darwin_event_thread_main (void *arg0) { - IOReturn kresult; - struct libusb_context *ctx = (struct libusb_context *)arg0; - CFRunLoopRef runloop; - - /* Set this thread's name, so it can be seen in the debugger - and crash reports. */ -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 - pthread_setname_np ("org.libusb.device-hotplug"); - - /* Tell the Objective-C garbage collector about this thread. - This is required because, unlike NSThreads, pthreads are - not automatically registered. Although we don't use - Objective-C, we use CoreFoundation, which does. */ - objc_registerThreadWithCollector(); -#endif - - /* hotplug (device arrival/removal) sources */ - CFRunLoopSourceRef libusb_notification_cfsource; - io_notification_port_t libusb_notification_port; - io_iterator_t libusb_rem_device_iterator; - io_iterator_t libusb_add_device_iterator; - - usbi_dbg ("creating hotplug event source"); - - runloop = CFRunLoopGetCurrent (); - CFRetain (runloop); - - /* add the notification port to the run loop */ - libusb_notification_port = IONotificationPortCreate (kIOMasterPortDefault); - libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port); - CFRunLoopAddSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode); - - /* create notifications for removed devices */ - kresult = IOServiceAddMatchingNotification (libusb_notification_port, kIOTerminatedNotification, - IOServiceMatching(kIOUSBDeviceClassName), - (IOServiceMatchingCallback)darwin_devices_detached, - (void *)ctx, &libusb_rem_device_iterator); - - if (kresult != kIOReturnSuccess) { - usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult)); - - pthread_exit (NULL); - } - - /* create notifications for attached devices */ - kresult = IOServiceAddMatchingNotification(libusb_notification_port, kIOFirstMatchNotification, - IOServiceMatching(kIOUSBDeviceClassName), - (IOServiceMatchingCallback)darwin_devices_attached, - (void *)ctx, &libusb_add_device_iterator); - - if (kresult != kIOReturnSuccess) { - usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult)); - - pthread_exit (NULL); - } - - /* arm notifiers */ - darwin_clear_iterator (libusb_rem_device_iterator); - darwin_clear_iterator (libusb_add_device_iterator); - - usbi_dbg ("darwin event thread ready to receive events"); - - /* signal the main thread that the hotplug runloop has been created. */ - pthread_mutex_lock (&libusb_darwin_at_mutex); - libusb_darwin_acfl = runloop; - pthread_cond_signal (&libusb_darwin_at_cond); - pthread_mutex_unlock (&libusb_darwin_at_mutex); - - /* run the runloop */ - CFRunLoopRun(); - - usbi_dbg ("darwin event thread exiting"); - - /* remove the notification cfsource */ - CFRunLoopRemoveSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode); - - /* delete notification port */ - IONotificationPortDestroy (libusb_notification_port); - - /* delete iterators */ - IOObjectRelease (libusb_rem_device_iterator); - IOObjectRelease (libusb_add_device_iterator); - - CFRelease (runloop); - - libusb_darwin_acfl = NULL; - - pthread_exit (NULL); -} - -static void _darwin_finalize(void) { - struct darwin_cached_device *dev, *next; - - usbi_mutex_lock(&darwin_cached_devices_lock); - list_for_each_entry_safe(dev, next, &darwin_cached_devices, list, struct darwin_cached_device) { - darwin_deref_cached_device(dev); - } - usbi_mutex_unlock(&darwin_cached_devices_lock); -} - -static int darwin_init(struct libusb_context *ctx) { - host_name_port_t host_self; - static int initted = 0; - int rc; - - rc = darwin_scan_devices (ctx); - if (LIBUSB_SUCCESS != rc) { - return rc; - } - - if (OSAtomicIncrement32Barrier(&initCount) == 1) { - /* create the clocks that will be used */ - - if (!initted) { - initted = 1; - atexit(_darwin_finalize); - } - - host_self = mach_host_self(); - host_get_clock_service(host_self, CALENDAR_CLOCK, &clock_realtime); - host_get_clock_service(host_self, SYSTEM_CLOCK, &clock_monotonic); - mach_port_deallocate(mach_task_self(), host_self); - - pthread_create (&libusb_darwin_at, NULL, darwin_event_thread_main, (void *)ctx); - - pthread_mutex_lock (&libusb_darwin_at_mutex); - while (!libusb_darwin_acfl) - pthread_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex); - pthread_mutex_unlock (&libusb_darwin_at_mutex); - } - - return rc; -} - -static void darwin_exit (void) { - if (OSAtomicDecrement32Barrier(&initCount) == 0) { - mach_port_deallocate(mach_task_self(), clock_realtime); - mach_port_deallocate(mach_task_self(), clock_monotonic); - - /* stop the event runloop and wait for the thread to terminate. */ - CFRunLoopStop (libusb_darwin_acfl); - pthread_join (libusb_darwin_at, NULL); - } -} - -static int darwin_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) { - struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev); - - /* return cached copy */ - memmove (buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH); - - *host_endian = 0; - - return 0; -} - -static int get_configuration_index (struct libusb_device *dev, int config_value) { - struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev); - UInt8 i, numConfig; - IOUSBConfigurationDescriptorPtr desc; - IOReturn kresult; - - /* is there a simpler way to determine the index? */ - kresult = (*(priv->device))->GetNumberOfConfigurations (priv->device, &numConfig); - if (kresult != kIOReturnSuccess) - return darwin_to_libusb (kresult); - - for (i = 0 ; i < numConfig ; i++) { - (*(priv->device))->GetConfigurationDescriptorPtr (priv->device, i, &desc); - - if (desc->bConfigurationValue == config_value) - return i; - } - - /* configuration not found */ - return LIBUSB_ERROR_NOT_FOUND; -} - -static int darwin_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) { - struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev); - int config_index; - - if (0 == priv->active_config) - return LIBUSB_ERROR_NOT_FOUND; - - config_index = get_configuration_index (dev, priv->active_config); - if (config_index < 0) - return config_index; - - return darwin_get_config_descriptor (dev, config_index, buffer, len, host_endian); -} - -static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) { - struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev); - IOUSBConfigurationDescriptorPtr desc; - IOReturn kresult; - int ret; - - if (!priv || !priv->device) - return LIBUSB_ERROR_OTHER; - - kresult = (*priv->device)->GetConfigurationDescriptorPtr (priv->device, config_index, &desc); - if (kresult == kIOReturnSuccess) { - /* copy descriptor */ - if (libusb_le16_to_cpu(desc->wTotalLength) < len) - len = libusb_le16_to_cpu(desc->wTotalLength); - - memmove (buffer, desc, len); - - /* GetConfigurationDescriptorPtr returns the descriptor in USB bus order */ - *host_endian = 0; - } - - ret = darwin_to_libusb (kresult); - if (ret != LIBUSB_SUCCESS) - return ret; - - return len; -} - -/* check whether the os has configured the device */ -static int darwin_check_configuration (struct libusb_context *ctx, struct darwin_cached_device *dev) { - usb_device_t **darwin_device = dev->device; - - IOUSBConfigurationDescriptorPtr configDesc; - IOUSBFindInterfaceRequest request; - kern_return_t kresult; - io_iterator_t interface_iterator; - io_service_t firstInterface; - - if (dev->dev_descriptor.bNumConfigurations < 1) { - usbi_err (ctx, "device has no configurations"); - return LIBUSB_ERROR_OTHER; /* no configurations at this speed so we can't use it */ - } - - /* find the first configuration */ - kresult = (*darwin_device)->GetConfigurationDescriptorPtr (darwin_device, 0, &configDesc); - dev->first_config = (kIOReturnSuccess == kresult) ? configDesc->bConfigurationValue : 1; - - /* check if the device is already configured. there is probably a better way than iterating over the - to accomplish this (the trick is we need to avoid a call to GetConfigurations since buggy devices - might lock up on the device request) */ - - /* Setup the Interface Request */ - request.bInterfaceClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; - request.bAlternateSetting = kIOUSBFindInterfaceDontCare; - - kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator); - if (kresult) - return darwin_to_libusb (kresult); - - /* iterate once */ - firstInterface = IOIteratorNext(interface_iterator); - - /* done with the interface iterator */ - IOObjectRelease(interface_iterator); - - if (firstInterface) { - IOObjectRelease (firstInterface); - - /* device is configured */ - if (dev->dev_descriptor.bNumConfigurations == 1) - /* to avoid problems with some devices get the configurations value from the configuration descriptor */ - dev->active_config = dev->first_config; - else - /* devices with more than one configuration should work with GetConfiguration */ - (*darwin_device)->GetConfiguration (darwin_device, &dev->active_config); - } else - /* not configured */ - dev->active_config = 0; - - usbi_dbg ("active config: %u, first config: %u", dev->active_config, dev->first_config); - - return 0; -} - -static int darwin_request_descriptor (usb_device_t **device, UInt8 desc, UInt8 desc_index, void *buffer, size_t buffer_size) { - IOUSBDevRequestTO req; - - memset (buffer, 0, buffer_size); - - /* Set up request for descriptor/ */ - req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); - req.bRequest = kUSBRqGetDescriptor; - req.wValue = desc << 8; - req.wIndex = desc_index; - req.wLength = buffer_size; - req.pData = buffer; - req.noDataTimeout = 20; - req.completionTimeout = 100; - - return (*device)->DeviceRequestTO (device, &req); -} - -static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct darwin_cached_device *dev) { - usb_device_t **device = dev->device; - int retries = 1, delay = 30000; - int unsuspended = 0, try_unsuspend = 1, try_reconfigure = 1; - int is_open = 0; - int ret = 0, ret2; - UInt8 bDeviceClass; - UInt16 idProduct, idVendor; - - dev->can_enumerate = 0; - - (*device)->GetDeviceClass (device, &bDeviceClass); - (*device)->GetDeviceProduct (device, &idProduct); - (*device)->GetDeviceVendor (device, &idVendor); - - /* According to Apple's documentation the device must be open for DeviceRequest but we may not be able to open some - * devices and Apple's USB Prober doesn't bother to open the device before issuing a descriptor request. Still, - * to follow the spec as closely as possible, try opening the device */ - is_open = ((*device)->USBDeviceOpenSeize(device) == kIOReturnSuccess); - - do { - /**** retrieve device descriptor ****/ - ret = darwin_request_descriptor (device, kUSBDeviceDesc, 0, &dev->dev_descriptor, sizeof(dev->dev_descriptor)); - - if (kIOReturnOverrun == ret && kUSBDeviceDesc == dev->dev_descriptor.bDescriptorType) - /* received an overrun error but we still received a device descriptor */ - ret = kIOReturnSuccess; - - if (kIOUSBVendorIDAppleComputer == idVendor) { - /* NTH: don't bother retrying or unsuspending Apple devices */ - break; - } - - if (kIOReturnSuccess == ret && (0 == dev->dev_descriptor.bNumConfigurations || - 0 == dev->dev_descriptor.bcdUSB)) { - /* work around for incorrectly configured devices */ - if (try_reconfigure && is_open) { - usbi_dbg("descriptor appears to be invalid. resetting configuration before trying again..."); - - /* set the first configuration */ - (*device)->SetConfiguration(device, 1); - - /* don't try to reconfigure again */ - try_reconfigure = 0; - } - - ret = kIOUSBPipeStalled; - } - - if (kIOReturnSuccess != ret && is_open && try_unsuspend) { - /* device may be suspended. unsuspend it and try again */ -#if DeviceVersion >= 320 - UInt32 info = 0; - - /* IOUSBFamily 320+ provides a way to detect device suspension but earlier versions do not */ - (void)(*device)->GetUSBDeviceInformation (device, &info); - - /* note that the device was suspended */ - if (info & (1 << kUSBInformationDeviceIsSuspendedBit) || 0 == info) - try_unsuspend = 1; -#endif - - if (try_unsuspend) { - /* try to unsuspend the device */ - ret2 = (*device)->USBDeviceSuspend (device, 0); - if (kIOReturnSuccess != ret2) { - /* prevent log spew from poorly behaving devices. this indicates the - os actually had trouble communicating with the device */ - usbi_dbg("could not retrieve device descriptor. failed to unsuspend: %s",darwin_error_str(ret2)); - } else - unsuspended = 1; - - try_unsuspend = 0; - } - } - - if (kIOReturnSuccess != ret) { - usbi_dbg("kernel responded with code: 0x%08x. sleeping for %d ms before trying again", ret, delay/1000); - /* sleep for a little while before trying again */ - usleep (delay); - } - } while (kIOReturnSuccess != ret && retries--); - - if (unsuspended) - /* resuspend the device */ - (void)(*device)->USBDeviceSuspend (device, 1); - - if (is_open) - (void) (*device)->USBDeviceClose (device); - - if (ret != kIOReturnSuccess) { - /* a debug message was already printed out for this error */ - if (LIBUSB_CLASS_HUB == bDeviceClass) - usbi_dbg ("could not retrieve device descriptor %.4x:%.4x: %s (%x). skipping device", - idVendor, idProduct, darwin_error_str (ret), ret); - else - usbi_warn (ctx, "could not retrieve device descriptor %.4x:%.4x: %s (%x). skipping device", - idVendor, idProduct, darwin_error_str (ret), ret); - return -1; - } - - /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices. */ - if (libusb_le16_to_cpu (dev->dev_descriptor.idProduct) != idProduct) { - /* not a valid device */ - usbi_warn (ctx, "idProduct from iokit (%04x) does not match idProduct in descriptor (%04x). skipping device", - idProduct, libusb_le16_to_cpu (dev->dev_descriptor.idProduct)); - return -1; - } - - usbi_dbg ("cached device descriptor:"); - usbi_dbg (" bDescriptorType: 0x%02x", dev->dev_descriptor.bDescriptorType); - usbi_dbg (" bcdUSB: 0x%04x", dev->dev_descriptor.bcdUSB); - usbi_dbg (" bDeviceClass: 0x%02x", dev->dev_descriptor.bDeviceClass); - usbi_dbg (" bDeviceSubClass: 0x%02x", dev->dev_descriptor.bDeviceSubClass); - usbi_dbg (" bDeviceProtocol: 0x%02x", dev->dev_descriptor.bDeviceProtocol); - usbi_dbg (" bMaxPacketSize0: 0x%02x", dev->dev_descriptor.bMaxPacketSize0); - usbi_dbg (" idVendor: 0x%04x", dev->dev_descriptor.idVendor); - usbi_dbg (" idProduct: 0x%04x", dev->dev_descriptor.idProduct); - usbi_dbg (" bcdDevice: 0x%04x", dev->dev_descriptor.bcdDevice); - usbi_dbg (" iManufacturer: 0x%02x", dev->dev_descriptor.iManufacturer); - usbi_dbg (" iProduct: 0x%02x", dev->dev_descriptor.iProduct); - usbi_dbg (" iSerialNumber: 0x%02x", dev->dev_descriptor.iSerialNumber); - usbi_dbg (" bNumConfigurations: 0x%02x", dev->dev_descriptor.bNumConfigurations); - - dev->can_enumerate = 1; - - return 0; -} - -static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t service, - struct darwin_cached_device **cached_out) { - struct darwin_cached_device *new_device; - UInt64 sessionID, parent_sessionID; - int ret = LIBUSB_SUCCESS; - usb_device_t **device; - io_service_t parent; - kern_return_t result; - UInt8 port = 0; - - *cached_out = NULL; - - /* get some info from the io registry */ - (void) get_ioregistry_value_number (service, CFSTR("sessionID"), kCFNumberSInt64Type, &sessionID); - (void) get_ioregistry_value_number (service, CFSTR("PortNum"), kCFNumberSInt8Type, &port); - - usbi_dbg("finding cached device for sessionID 0x\n" PRIx64, sessionID); - - result = IORegistryEntryGetParentEntry (service, kIOUSBPlane, &parent); - - if (kIOReturnSuccess == result) { - (void) get_ioregistry_value_number (parent, CFSTR("sessionID"), kCFNumberSInt64Type, &parent_sessionID); - IOObjectRelease(parent); - } - - usbi_mutex_lock(&darwin_cached_devices_lock); - do { - list_for_each_entry(new_device, &darwin_cached_devices, list, struct darwin_cached_device) { - usbi_dbg("matching sessionID 0x%x against cached device with sessionID 0x%x", sessionID, new_device->session); - if (new_device->session == sessionID) { - usbi_dbg("using cached device for device"); - *cached_out = new_device; - break; - } - } - - if (*cached_out) - break; - - usbi_dbg("caching new device with sessionID 0x%x\n", sessionID); - - new_device = calloc (1, sizeof (*new_device)); - if (!new_device) { - ret = LIBUSB_ERROR_NO_MEM; - break; - } - - device = darwin_device_from_service (service); - if (!device) { - ret = LIBUSB_ERROR_NO_DEVICE; - free (new_device); - new_device = NULL; - break; - } - - /* add this device to the cached device list */ - list_add(&new_device->list, &darwin_cached_devices); - - (*device)->GetDeviceAddress (device, (USBDeviceAddress *)&new_device->address); - - /* keep a reference to this device */ - darwin_ref_cached_device(new_device); - - new_device->device = device; - new_device->session = sessionID; - (*device)->GetLocationID (device, &new_device->location); - new_device->port = port; - new_device->parent_session = parent_sessionID; - - /* cache the device descriptor */ - ret = darwin_cache_device_descriptor(ctx, new_device); - if (ret) - break; - - if (new_device->can_enumerate) { - snprintf(new_device->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", new_device->address, - new_device->dev_descriptor.idVendor, new_device->dev_descriptor.idProduct, - new_device->dev_descriptor.bDeviceClass, new_device->dev_descriptor.bDeviceSubClass); - } - } while (0); - - usbi_mutex_unlock(&darwin_cached_devices_lock); - - /* keep track of devices regardless of if we successfully enumerate them to - prevent them from being enumerated multiple times */ - - *cached_out = new_device; - - return ret; -} - -static int process_new_device (struct libusb_context *ctx, io_service_t service) { - struct darwin_device_priv *priv; - struct libusb_device *dev = NULL; - struct darwin_cached_device *cached_device; - UInt8 devSpeed; - int ret = 0; - - do { - ret = darwin_get_cached_device (ctx, service, &cached_device); - - if (ret < 0 || (cached_device && !cached_device->can_enumerate)) { - return ret; - } - - /* check current active configuration (and cache the first configuration value-- - which may be used by claim_interface) */ - ret = darwin_check_configuration (ctx, cached_device); - if (ret) - break; - - usbi_dbg ("allocating new device in context %p for with session 0x%08x", - ctx, cached_device->session); - - dev = usbi_alloc_device(ctx, cached_device->session); - if (!dev) { - return LIBUSB_ERROR_NO_MEM; - } - - priv = (struct darwin_device_priv *)dev->os_priv; - - priv->dev = cached_device; - darwin_ref_cached_device (priv->dev); - - if (cached_device->parent_session > 0) { - dev->parent_dev = usbi_get_device_by_session_id (ctx, cached_device->parent_session); - } else { - dev->parent_dev = NULL; - } - dev->port_number = cached_device->port; - dev->bus_number = cached_device->location >> 24; - dev->device_address = cached_device->address; - - /* need to add a reference to the parent device */ - if (dev->parent_dev) { - libusb_ref_device(dev->parent_dev); - } - - (*(priv->dev->device))->GetDeviceSpeed (priv->dev->device, &devSpeed); - - switch (devSpeed) { - case kUSBDeviceSpeedLow: dev->speed = LIBUSB_SPEED_LOW; break; - case kUSBDeviceSpeedFull: dev->speed = LIBUSB_SPEED_FULL; break; - case kUSBDeviceSpeedHigh: dev->speed = LIBUSB_SPEED_HIGH; break; -#if DeviceVersion >= 500 - case kUSBDeviceSpeedSuper: dev->speed = LIBUSB_SPEED_SUPER; break; -#endif - default: - usbi_warn (ctx, "Got unknown device speed %d", devSpeed); - } - - ret = usbi_sanitize_device (dev); - if (ret < 0) - break; - - usbi_dbg ("found device with address %d port = %d parent = %p at %p", dev->device_address, - dev->port_number, (void *) dev->parent_dev, priv->dev->sys_path); - } while (0); - - if (0 == ret) { - usbi_connect_device (dev); - } else { - libusb_unref_device (dev); - } - - return ret; -} - -static int darwin_scan_devices(struct libusb_context *ctx) { - io_iterator_t deviceIterator; - io_service_t service; - kern_return_t kresult; - - kresult = usb_setup_device_iterator (&deviceIterator, 0); - if (kresult != kIOReturnSuccess) - return darwin_to_libusb (kresult); - - while ((service = IOIteratorNext (deviceIterator))) { - (void) process_new_device (ctx, service); - - IOObjectRelease(service); - } - - IOObjectRelease(deviceIterator); - - return 0; -} - -static int darwin_open (struct libusb_device_handle *dev_handle) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); - IOReturn kresult; - - if (0 == dpriv->open_count) { - /* try to open the device */ - kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device); - if (kresult != kIOReturnSuccess) { - usbi_warn (HANDLE_CTX (dev_handle), "USBDeviceOpen: %s", darwin_error_str(kresult)); - - if (kIOReturnExclusiveAccess != kresult) { - return darwin_to_libusb (kresult); - } - - /* it is possible to perform some actions on a device that is not open so do not return an error */ - priv->is_open = 0; - } else { - priv->is_open = 1; - } - - /* create async event source */ - kresult = (*(dpriv->device))->CreateDeviceAsyncEventSource (dpriv->device, &priv->cfSource); - if (kresult != kIOReturnSuccess) { - usbi_err (HANDLE_CTX (dev_handle), "CreateDeviceAsyncEventSource: %s", darwin_error_str(kresult)); - - if (priv->is_open) { - (*(dpriv->device))->USBDeviceClose (dpriv->device); - } - - priv->is_open = 0; - - return darwin_to_libusb (kresult); - } - - CFRetain (libusb_darwin_acfl); - - /* add the cfSource to the aync run loop */ - CFRunLoopAddSource(libusb_darwin_acfl, priv->cfSource, kCFRunLoopCommonModes); - } - - /* device opened successfully */ - dpriv->open_count++; - - /* create a file descriptor for notifications */ - pipe (priv->fds); - - /* set the pipe to be non-blocking */ - fcntl (priv->fds[1], F_SETFD, O_NONBLOCK); - - usbi_add_pollfd(HANDLE_CTX(dev_handle), priv->fds[0], POLLIN); - - usbi_dbg ("device open for access"); - - return 0; -} - -static void darwin_close (struct libusb_device_handle *dev_handle) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); - IOReturn kresult; - int i; - - if (dpriv->open_count == 0) { - /* something is probably very wrong if this is the case */ - usbi_err (HANDLE_CTX (dev_handle), "Close called on a device that was not open!\n"); - return; - } - - dpriv->open_count--; - - /* make sure all interfaces are released */ - for (i = 0 ; i < USB_MAXINTERFACES ; i++) - if (dev_handle->claimed_interfaces & (1 << i)) - libusb_release_interface (dev_handle, i); - - if (0 == dpriv->open_count) { - /* delete the device's async event source */ - if (priv->cfSource) { - CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode); - CFRelease (priv->cfSource); - priv->cfSource = NULL; - CFRelease (libusb_darwin_acfl); - } - - if (priv->is_open) { - /* close the device */ - kresult = (*(dpriv->device))->USBDeviceClose(dpriv->device); - if (kresult) { - /* Log the fact that we had a problem closing the file, however failing a - * close isn't really an error, so return success anyway */ - usbi_warn (HANDLE_CTX (dev_handle), "USBDeviceClose: %s", darwin_error_str(kresult)); - } - } - } - - /* file descriptors are maintained per-instance */ - usbi_remove_pollfd (HANDLE_CTX (dev_handle), priv->fds[0]); - close (priv->fds[1]); - close (priv->fds[0]); - - priv->fds[0] = priv->fds[1] = -1; -} - -static int darwin_get_configuration(struct libusb_device_handle *dev_handle, int *config) { - struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); - - *config = (int) dpriv->active_config; - - return 0; -} - -static int darwin_set_configuration(struct libusb_device_handle *dev_handle, int config) { - struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); - IOReturn kresult; - int i; - - /* Setting configuration will invalidate the interface, so we need - to reclaim it. First, dispose of existing interfaces, if any. */ - for (i = 0 ; i < USB_MAXINTERFACES ; i++) - if (dev_handle->claimed_interfaces & (1 << i)) - darwin_release_interface (dev_handle, i); - - kresult = (*(dpriv->device))->SetConfiguration (dpriv->device, config); - if (kresult != kIOReturnSuccess) - return darwin_to_libusb (kresult); - - /* Reclaim any interfaces. */ - for (i = 0 ; i < USB_MAXINTERFACES ; i++) - if (dev_handle->claimed_interfaces & (1 << i)) - darwin_claim_interface (dev_handle, i); - - dpriv->active_config = config; - - return 0; -} - -static int darwin_get_interface (usb_device_t **darwin_device, uint8_t ifc, io_service_t *usbInterfacep) { - IOUSBFindInterfaceRequest request; - kern_return_t kresult; - io_iterator_t interface_iterator; - UInt8 bInterfaceNumber; - int ret; - - *usbInterfacep = IO_OBJECT_NULL; - - /* Setup the Interface Request */ - request.bInterfaceClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; - request.bAlternateSetting = kIOUSBFindInterfaceDontCare; - - kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator); - if (kresult) - return kresult; - - while ((*usbInterfacep = IOIteratorNext(interface_iterator))) { - /* find the interface number */ - ret = get_ioregistry_value_number (*usbInterfacep, CFSTR("bInterfaceNumber"), kCFNumberSInt8Type, - &bInterfaceNumber); - - if (ret && bInterfaceNumber == ifc) { - break; - } - - (void) IOObjectRelease (*usbInterfacep); - } - - /* done with the interface iterator */ - IOObjectRelease(interface_iterator); - - return 0; -} - -static int get_endpoints (struct libusb_device_handle *dev_handle, int iface) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - - /* current interface */ - struct darwin_interface *cInterface = &priv->interfaces[iface]; - - kern_return_t kresult; - - u_int8_t numep, direction, number; - u_int8_t dont_care1, dont_care3; - u_int16_t dont_care2; - int i; - - usbi_dbg ("building table of endpoints."); - - /* retrieve the total number of endpoints on this interface */ - kresult = (*(cInterface->interface))->GetNumEndpoints(cInterface->interface, &numep); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "can't get number of endpoints for interface: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - - /* iterate through pipe references */ - for (i = 1 ; i <= numep ; i++) { - kresult = (*(cInterface->interface))->GetPipeProperties(cInterface->interface, i, &direction, &number, &dont_care1, - &dont_care2, &dont_care3); - - if (kresult != kIOReturnSuccess) { - usbi_err (HANDLE_CTX (dev_handle), "error getting pipe information for pipe %d: %s", i, darwin_error_str(kresult)); - - return darwin_to_libusb (kresult); - } - - usbi_dbg ("interface: %i pipe %i: dir: %i number: %i", iface, i, direction, number); - - cInterface->endpoint_addrs[i - 1] = ((direction << 7 & LIBUSB_ENDPOINT_DIR_MASK) | (number & LIBUSB_ENDPOINT_ADDRESS_MASK)); - } - - cInterface->num_endpoints = numep; - - return 0; -} - -static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface) { - struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - io_service_t usbInterface = IO_OBJECT_NULL; - IOReturn kresult; - IOCFPlugInInterface **plugInInterface = NULL; - SInt32 score; - - /* current interface */ - struct darwin_interface *cInterface = &priv->interfaces[iface]; - - kresult = darwin_get_interface (dpriv->device, iface, &usbInterface); - if (kresult != kIOReturnSuccess) - return darwin_to_libusb (kresult); - - /* make sure we have an interface */ - if (!usbInterface && dpriv->first_config != 0) { - usbi_info (HANDLE_CTX (dev_handle), "no interface found; setting configuration: %d", dpriv->first_config); - - /* set the configuration */ - kresult = darwin_set_configuration (dev_handle, dpriv->first_config); - if (kresult != LIBUSB_SUCCESS) { - usbi_err (HANDLE_CTX (dev_handle), "could not set configuration"); - return kresult; - } - - kresult = darwin_get_interface (dpriv->device, iface, &usbInterface); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - } - - if (!usbInterface) { - usbi_err (HANDLE_CTX (dev_handle), "interface not found"); - return LIBUSB_ERROR_NOT_FOUND; - } - - /* get an interface to the device's interface */ - kresult = IOCreatePlugInInterfaceForService (usbInterface, kIOUSBInterfaceUserClientTypeID, - kIOCFPlugInInterfaceID, &plugInInterface, &score); - - /* ignore release error */ - (void)IOObjectRelease (usbInterface); - - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "IOCreatePlugInInterfaceForService: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - - if (!plugInInterface) { - usbi_err (HANDLE_CTX (dev_handle), "plugin interface not found"); - return LIBUSB_ERROR_NOT_FOUND; - } - - /* Do the actual claim */ - kresult = (*plugInInterface)->QueryInterface(plugInInterface, - CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), - (LPVOID)&cInterface->interface); - /* We no longer need the intermediate plug-in */ - /* Use release instead of IODestroyPlugInInterface to avoid stopping IOServices associated with this device */ - (*plugInInterface)->Release (plugInInterface); - if (kresult || !cInterface->interface) { - usbi_err (HANDLE_CTX (dev_handle), "QueryInterface: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - - /* claim the interface */ - kresult = (*(cInterface->interface))->USBInterfaceOpen(cInterface->interface); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "USBInterfaceOpen: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - - /* update list of endpoints */ - kresult = get_endpoints (dev_handle, iface); - if (kresult) { - /* this should not happen */ - darwin_release_interface (dev_handle, iface); - usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table"); - return kresult; - } - - cInterface->cfSource = NULL; - - /* create async event source */ - kresult = (*(cInterface->interface))->CreateInterfaceAsyncEventSource (cInterface->interface, &cInterface->cfSource); - if (kresult != kIOReturnSuccess) { - usbi_err (HANDLE_CTX (dev_handle), "could not create async event source"); - - /* can't continue without an async event source */ - (void)darwin_release_interface (dev_handle, iface); - - return darwin_to_libusb (kresult); - } - - /* add the cfSource to the async thread's run loop */ - CFRunLoopAddSource(libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode); - - usbi_dbg ("interface opened"); - - return 0; -} - -static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - IOReturn kresult; - - /* current interface */ - struct darwin_interface *cInterface = &priv->interfaces[iface]; - - /* Check to see if an interface is open */ - if (!cInterface->interface) - return LIBUSB_SUCCESS; - - /* clean up endpoint data */ - cInterface->num_endpoints = 0; - - /* delete the interface's async event source */ - if (cInterface->cfSource) { - CFRunLoopRemoveSource (libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode); - CFRelease (cInterface->cfSource); - } - - kresult = (*(cInterface->interface))->USBInterfaceClose(cInterface->interface); - if (kresult) - usbi_warn (HANDLE_CTX (dev_handle), "USBInterfaceClose: %s", darwin_error_str(kresult)); - - kresult = (*(cInterface->interface))->Release(cInterface->interface); - if (kresult != kIOReturnSuccess) - usbi_warn (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult)); - - cInterface->interface = IO_OBJECT_NULL; - - return darwin_to_libusb (kresult); -} - -static int darwin_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - IOReturn kresult; - - /* current interface */ - struct darwin_interface *cInterface = &priv->interfaces[iface]; - - if (!cInterface->interface) - return LIBUSB_ERROR_NO_DEVICE; - - kresult = (*(cInterface->interface))->SetAlternateInterface (cInterface->interface, altsetting); - if (kresult != kIOReturnSuccess) - darwin_reset_device (dev_handle); - - /* update list of endpoints */ - kresult = get_endpoints (dev_handle, iface); - if (kresult) { - /* this should not happen */ - darwin_release_interface (dev_handle, iface); - usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table"); - return kresult; - } - - return darwin_to_libusb (kresult); -} - -static int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - - /* current interface */ - struct darwin_interface *cInterface; - uint8_t pipeRef, iface; - IOReturn kresult; - - /* determine the interface/endpoint to use */ - if (ep_to_pipeRef (dev_handle, endpoint, &pipeRef, &iface) != 0) { - usbi_err (HANDLE_CTX (dev_handle), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - - /* newer versions of darwin support clearing additional bits on the device's endpoint */ - kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef); - if (kresult) - usbi_warn (HANDLE_CTX (dev_handle), "ClearPipeStall: %s", darwin_error_str (kresult)); - - return darwin_to_libusb (kresult); -} - -static int darwin_reset_device(struct libusb_device_handle *dev_handle) { - struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); - IOUSBDeviceDescriptor descriptor; - IOUSBConfigurationDescriptorPtr cached_configuration; - IOUSBConfigurationDescriptor configuration; - bool reenumerate = false; - IOReturn kresult; - int i; - - kresult = (*(dpriv->device))->ResetDevice (dpriv->device); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "ResetDevice: %s", darwin_error_str (kresult)); - return darwin_to_libusb (kresult); - } - - do { - usbi_dbg ("darwin/reset_device: checking if device descriptor changed"); - - /* ignore return code. if we can't get a descriptor it might be worthwhile re-enumerating anway */ - (void) darwin_request_descriptor (dpriv->device, kUSBDeviceDesc, 0, &descriptor, sizeof (descriptor)); - - /* check if the device descriptor has changed */ - if (0 != memcmp (&dpriv->dev_descriptor, &descriptor, sizeof (descriptor))) { - reenumerate = true; - break; - } - - /* check if any configuration descriptor has changed */ - for (i = 0 ; i < descriptor.bNumConfigurations ; ++i) { - usbi_dbg ("darwin/reset_device: checking if configuration descriptor %d changed", i); - - (void) darwin_request_descriptor (dpriv->device, kUSBConfDesc, i, &configuration, sizeof (configuration)); - (*(dpriv->device))->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration); - - if (!cached_configuration || 0 != memcmp (cached_configuration, &configuration, sizeof (configuration))) { - reenumerate = true; - break; - } - } - } while (0); - - if (reenumerate) { - usbi_dbg ("darwin/reset_device: device requires reenumeration"); - (void) (*(dpriv->device))->USBDeviceReEnumerate (dpriv->device, 0); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg ("darwin/reset_device: device reset complete"); - - return LIBUSB_SUCCESS; -} - -static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, int interface) { - struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev); - io_service_t usbInterface; - CFTypeRef driver; - IOReturn kresult; - - kresult = darwin_get_interface (dpriv->device, interface, &usbInterface); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult)); - - return darwin_to_libusb (kresult); - } - - driver = IORegistryEntryCreateCFProperty (usbInterface, kIOBundleIdentifierKey, kCFAllocatorDefault, 0); - IOObjectRelease (usbInterface); - - if (driver) { - CFRelease (driver); - - return 1; - } - - /* no driver */ - return 0; -} - -/* attaching/detaching kernel drivers is not currently supported (maybe in the future?) */ -static int darwin_attach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) { - (void)dev_handle; - (void)interface; - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) { - (void)dev_handle; - (void)interface; - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static void darwin_destroy_device(struct libusb_device *dev) { - struct darwin_device_priv *dpriv = (struct darwin_device_priv *) dev->os_priv; - - if (dpriv->dev) { - /* need to hold the lock in case this is the last reference to the device */ - usbi_mutex_lock(&darwin_cached_devices_lock); - darwin_deref_cached_device (dpriv->dev); - dpriv->dev = NULL; - usbi_mutex_unlock(&darwin_cached_devices_lock); - } -} - -static int submit_bulk_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - - IOReturn ret; - uint8_t transferType; - /* None of the values below are used in libusbx for bulk transfers */ - uint8_t direction, number, interval, pipeRef, iface; - uint16_t maxPacketSize; - - struct darwin_interface *cInterface; - - if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { - usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - - (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number, - &transferType, &maxPacketSize, &interval); - - if (0 != (transfer->length % maxPacketSize)) { - /* do not need a zero packet */ - transfer->flags &= ~LIBUSB_TRANSFER_ADD_ZERO_PACKET; - } - - /* submit the request */ - /* timeouts are unavailable on interrupt endpoints */ - if (transferType == kUSBInterrupt) { - if (IS_XFERIN(transfer)) - ret = (*(cInterface->interface))->ReadPipeAsync(cInterface->interface, pipeRef, transfer->buffer, - transfer->length, darwin_async_io_callback, itransfer); - else - ret = (*(cInterface->interface))->WritePipeAsync(cInterface->interface, pipeRef, transfer->buffer, - transfer->length, darwin_async_io_callback, itransfer); - } else { - itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT; - - if (IS_XFERIN(transfer)) - ret = (*(cInterface->interface))->ReadPipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer, - transfer->length, transfer->timeout, transfer->timeout, - darwin_async_io_callback, (void *)itransfer); - else - ret = (*(cInterface->interface))->WritePipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer, - transfer->length, transfer->timeout, transfer->timeout, - darwin_async_io_callback, (void *)itransfer); - } - - if (ret) - usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", IS_XFERIN(transfer) ? "In" : "Out", - darwin_error_str(ret), ret); - - return darwin_to_libusb (ret); -} - -static int submit_iso_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - - IOReturn kresult; - uint8_t direction, number, interval, pipeRef, iface, transferType; - uint16_t maxPacketSize; - UInt64 frame; - AbsoluteTime atTime; - int i; - - struct darwin_interface *cInterface; - - /* construct an array of IOUSBIsocFrames, reuse the old one if possible */ - if (tpriv->isoc_framelist && tpriv->num_iso_packets != transfer->num_iso_packets) { - free(tpriv->isoc_framelist); - tpriv->isoc_framelist = NULL; - } - - if (!tpriv->isoc_framelist) { - tpriv->num_iso_packets = transfer->num_iso_packets; - tpriv->isoc_framelist = (IOUSBIsocFrame*) calloc (transfer->num_iso_packets, sizeof(IOUSBIsocFrame)); - if (!tpriv->isoc_framelist) - return LIBUSB_ERROR_NO_MEM; - } - - /* copy the frame list from the libusbx descriptor (the structures differ only is member order) */ - for (i = 0 ; i < transfer->num_iso_packets ; i++) - tpriv->isoc_framelist[i].frReqCount = transfer->iso_packet_desc[i].length; - - /* determine the interface/endpoint to use */ - if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { - usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - - /* determine the properties of this endpoint and the speed of the device */ - (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number, - &transferType, &maxPacketSize, &interval); - - /* Last but not least we need the bus frame number */ - kresult = (*(cInterface->interface))->GetBusFrameNumber(cInterface->interface, &frame, &atTime); - if (kresult) { - usbi_err (TRANSFER_CTX (transfer), "failed to get bus frame number: %d", kresult); - free(tpriv->isoc_framelist); - tpriv->isoc_framelist = NULL; - - return darwin_to_libusb (kresult); - } - - (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number, - &transferType, &maxPacketSize, &interval); - - /* schedule for a frame a little in the future */ - frame += 4; - - if (cInterface->frames[transfer->endpoint] && frame < cInterface->frames[transfer->endpoint]) - frame = cInterface->frames[transfer->endpoint]; - - /* submit the request */ - if (IS_XFERIN(transfer)) - kresult = (*(cInterface->interface))->ReadIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame, - transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback, - itransfer); - else - kresult = (*(cInterface->interface))->WriteIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame, - transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback, - itransfer); - - if (LIBUSB_SPEED_FULL == transfer->dev_handle->dev->speed) - /* Full speed */ - cInterface->frames[transfer->endpoint] = frame + transfer->num_iso_packets * (1 << (interval - 1)); - else - /* High/super speed */ - cInterface->frames[transfer->endpoint] = frame + transfer->num_iso_packets * (1 << (interval - 1)) / 8; - - if (kresult != kIOReturnSuccess) { - usbi_err (TRANSFER_CTX (transfer), "isochronous transfer failed (dir: %s): %s", IS_XFERIN(transfer) ? "In" : "Out", - darwin_error_str(kresult)); - free (tpriv->isoc_framelist); - tpriv->isoc_framelist = NULL; - } - - return darwin_to_libusb (kresult); -} - -static int submit_control_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_control_setup *setup = (struct libusb_control_setup *) transfer->buffer; - struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - - IOReturn kresult; - - bzero(&tpriv->req, sizeof(tpriv->req)); - - /* IOUSBDeviceInterface expects the request in cpu endianess */ - tpriv->req.bmRequestType = setup->bmRequestType; - tpriv->req.bRequest = setup->bRequest; - /* these values should be in bus order from libusb_fill_control_setup */ - tpriv->req.wValue = OSSwapLittleToHostInt16 (setup->wValue); - tpriv->req.wIndex = OSSwapLittleToHostInt16 (setup->wIndex); - tpriv->req.wLength = OSSwapLittleToHostInt16 (setup->wLength); - /* data is stored after the libusbx control block */ - tpriv->req.pData = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; - tpriv->req.completionTimeout = transfer->timeout; - tpriv->req.noDataTimeout = transfer->timeout; - - itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT; - - /* all transfers in libusb-1.0 are async */ - - if (transfer->endpoint) { - struct darwin_interface *cInterface; - uint8_t pipeRef, iface; - - if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { - usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - - kresult = (*(cInterface->interface))->ControlRequestAsyncTO (cInterface->interface, pipeRef, &(tpriv->req), darwin_async_io_callback, itransfer); - } else - /* control request on endpoint 0 */ - kresult = (*(dpriv->device))->DeviceRequestAsyncTO(dpriv->device, &(tpriv->req), darwin_async_io_callback, itransfer); - - if (kresult != kIOReturnSuccess) - usbi_err (TRANSFER_CTX (transfer), "control request failed: %s", darwin_error_str(kresult)); - - return darwin_to_libusb (kresult); -} - -static int darwin_submit_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return submit_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return submit_bulk_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return submit_iso_transfer(itransfer); - default: - usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static int cancel_control_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev); - IOReturn kresult; - - usbi_warn (ITRANSFER_CTX (itransfer), "aborting all transactions control pipe"); - - if (!dpriv->device) - return LIBUSB_ERROR_NO_DEVICE; - - kresult = (*(dpriv->device))->USBDeviceAbortPipeZero (dpriv->device); - - return darwin_to_libusb (kresult); -} - -static int darwin_abort_transfers (struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - struct darwin_interface *cInterface; - uint8_t pipeRef, iface; - IOReturn kresult; - - if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { - usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - - if (!dpriv->device) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_warn (ITRANSFER_CTX (itransfer), "aborting all transactions on interface %d pipe %d", iface, pipeRef); - - /* abort transactions */ - (*(cInterface->interface))->AbortPipe (cInterface->interface, pipeRef); - - usbi_dbg ("calling clear pipe stall to clear the data toggle bit"); - - /* newer versions of darwin support clearing additional bits on the device's endpoint */ - kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef); - - return darwin_to_libusb (kresult); -} - -static int darwin_cancel_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return cancel_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return darwin_abort_transfers (itransfer); - default: - usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static void darwin_clear_transfer_priv (struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - - if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS && tpriv->isoc_framelist) { - free (tpriv->isoc_framelist); - tpriv->isoc_framelist = NULL; - } -} - -static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0) { - struct usbi_transfer *itransfer = (struct usbi_transfer *)refcon; - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - struct darwin_msg_async_io_complete message = {.itransfer = itransfer, .result = result, - .size = (UInt32) (uintptr_t) arg0}; - - usbi_dbg ("an async io operation has completed"); - - /* if requested write a zero packet */ - if (kIOReturnSuccess == result && IS_XFEROUT(transfer) && transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) { - struct darwin_interface *cInterface; - uint8_t iface, pipeRef; - - (void) ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface); - cInterface = &priv->interfaces[iface]; - - (*(cInterface->interface))->WritePipe (cInterface->interface, pipeRef, transfer->buffer, 0); - } - - /* send a completion message to the device's file descriptor */ - write (priv->fds[1], &message, sizeof (message)); -} - -static int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_t result) { - if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) - result = kIOUSBTransactionTimeout; - - switch (result) { - case kIOReturnUnderrun: - case kIOReturnSuccess: - return LIBUSB_TRANSFER_COMPLETED; - case kIOReturnAborted: - return LIBUSB_TRANSFER_CANCELLED; - case kIOUSBPipeStalled: - usbi_dbg ("transfer error: pipe is stalled"); - return LIBUSB_TRANSFER_STALL; - case kIOReturnOverrun: - usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: data overrun"); - return LIBUSB_TRANSFER_OVERFLOW; - case kIOUSBTransactionTimeout: - usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: timed out"); - itransfer->flags |= USBI_TRANSFER_TIMED_OUT; - return LIBUSB_TRANSFER_TIMED_OUT; - default: - usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: %s (value = 0x%08x)", darwin_error_str (result), result); - return LIBUSB_TRANSFER_ERROR; - } -} - -static void darwin_handle_callback (struct usbi_transfer *itransfer, kern_return_t result, UInt32 io_size) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - int isIsoc = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type; - int isBulk = LIBUSB_TRANSFER_TYPE_BULK == transfer->type; - int isControl = LIBUSB_TRANSFER_TYPE_CONTROL == transfer->type; - int isInterrupt = LIBUSB_TRANSFER_TYPE_INTERRUPT == transfer->type; - int i; - - if (!isIsoc && !isBulk && !isControl && !isInterrupt) { - usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return; - } - - usbi_dbg ("handling %s completion with kernel status %d", - isControl ? "control" : isBulk ? "bulk" : isIsoc ? "isoc" : "interrupt", result); - - if (kIOReturnSuccess == result || kIOReturnUnderrun == result) { - if (isIsoc && tpriv->isoc_framelist) { - /* copy isochronous results back */ - - for (i = 0; i < transfer->num_iso_packets ; i++) { - struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i]; - lib_desc->status = darwin_to_libusb (tpriv->isoc_framelist[i].frStatus); - lib_desc->actual_length = tpriv->isoc_framelist[i].frActCount; - } - } else if (!isIsoc) - itransfer->transferred += io_size; - } - - /* it is ok to handle cancelled transfers without calling usbi_handle_transfer_cancellation (we catch timeout transfers) */ - usbi_handle_transfer_completion (itransfer, darwin_transfer_status (itransfer, result)); -} - -static int op_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready) { - struct darwin_msg_async_io_complete message; - POLL_NFDS_TYPE i = 0; - ssize_t ret; - - usbi_mutex_lock(&ctx->open_devs_lock); - - for (i = 0; i < nfds && num_ready > 0; i++) { - struct pollfd *pollfd = &fds[i]; - - usbi_dbg ("checking fd %i with revents = %x", pollfd->fd, pollfd->revents); - - if (!pollfd->revents) - continue; - - num_ready--; - - if (pollfd->revents & POLLERR) { - /* this probably will never happen so ignore the error an move on. */ - continue; - } - - /* there is only one type of message */ - ret = read (pollfd->fd, &message, sizeof (message)); - if (ret < (ssize_t) sizeof (message)) { - usbi_dbg ("WARNING: short read on async io completion pipe\n"); - continue; - } - - darwin_handle_callback (message.itransfer, message.result, message.size); - } - - usbi_mutex_unlock(&ctx->open_devs_lock); - - return 0; -} - -static int darwin_clock_gettime(int clk_id, struct timespec *tp) { - mach_timespec_t sys_time; - clock_serv_t clock_ref; - - switch (clk_id) { - case USBI_CLOCK_REALTIME: - /* CLOCK_REALTIME represents time since the epoch */ - clock_ref = clock_realtime; - break; - case USBI_CLOCK_MONOTONIC: - /* use system boot time as reference for the monotonic clock */ - clock_ref = clock_monotonic; - break; - default: - return LIBUSB_ERROR_INVALID_PARAM; - } - - clock_get_time (clock_ref, &sys_time); - - tp->tv_sec = sys_time.tv_sec; - tp->tv_nsec = sys_time.tv_nsec; - - return 0; -} - -const struct usbi_os_backend darwin_backend = { - .name = "Darwin", - .caps = 0, - .init = darwin_init, - .exit = darwin_exit, - .get_device_list = NULL, /* not needed */ - .get_device_descriptor = darwin_get_device_descriptor, - .get_active_config_descriptor = darwin_get_active_config_descriptor, - .get_config_descriptor = darwin_get_config_descriptor, - - .open = darwin_open, - .close = darwin_close, - .get_configuration = darwin_get_configuration, - .set_configuration = darwin_set_configuration, - .claim_interface = darwin_claim_interface, - .release_interface = darwin_release_interface, - - .set_interface_altsetting = darwin_set_interface_altsetting, - .clear_halt = darwin_clear_halt, - .reset_device = darwin_reset_device, - - .kernel_driver_active = darwin_kernel_driver_active, - .detach_kernel_driver = darwin_detach_kernel_driver, - .attach_kernel_driver = darwin_attach_kernel_driver, - - .destroy_device = darwin_destroy_device, - - .submit_transfer = darwin_submit_transfer, - .cancel_transfer = darwin_cancel_transfer, - .clear_transfer_priv = darwin_clear_transfer_priv, - - .handle_events = op_handle_events, - - .clock_gettime = darwin_clock_gettime, - - .device_priv_size = sizeof(struct darwin_device_priv), - .device_handle_priv_size = sizeof(struct darwin_device_handle_priv), - .transfer_priv_size = sizeof(struct darwin_transfer_priv), - .add_iso_packet_size = 0, -}; diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/darwin_usb.h b/src/3rd_party-static/libusbx-1.0.16/libusb/os/darwin_usb.h deleted file mode 100644 index 53b8542b13..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/darwin_usb.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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 - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#if !defined(LIBUSB_DARWIN_H) -#define LIBUSB_DARWIN_H - -#include "libusbi.h" - -#include <IOKit/IOTypes.h> -#include <IOKit/IOCFBundle.h> -#include <IOKit/usb/IOUSBLib.h> -#include <IOKit/IOCFPlugIn.h> - -/* IOUSBInterfaceInferface */ -#if defined (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 InterfaceInterfaceID kIOUSBInterfaceInterfaceID300 -#define InterfaceVersion 300 - -#elif defined (kIOUSBInterfaceInterfaceID245) - -#define usb_interface_t IOUSBInterfaceInterface245 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245 -#define InterfaceVersion 245 - -#elif defined (kIOUSBInterfaceInterfaceID220) - -#define usb_interface_t IOUSBInterfaceInterface220 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220 -#define InterfaceVersion 220 - -#else - -#error "IOUSBFamily is too old. Please upgrade your OS" - -#endif - -/* IOUSBDeviceInterface */ -#if defined (kIOUSBDeviceInterfaceID500) - -#define usb_device_t IOUSBDeviceInterface500 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID500 -#define DeviceVersion 500 - -#elif defined (kIOUSBDeviceInterfaceID320) - -#define usb_device_t IOUSBDeviceInterface320 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID320 -#define DeviceVersion 320 - -#elif defined (kIOUSBDeviceInterfaceID300) - -#define usb_device_t IOUSBDeviceInterface300 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID300 -#define DeviceVersion 300 - -#elif defined (kIOUSBDeviceInterfaceID245) - -#define usb_device_t IOUSBDeviceInterface245 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID245 -#define DeviceVersion 245 - -#elif defined (kIOUSBDeviceInterfaceID220) -#define usb_device_t IOUSBDeviceInterface197 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID197 -#define DeviceVersion 197 - -#else - -#error "IOUSBFamily is too old. Please upgrade your OS" - -#endif - -#if !defined(IO_OBJECT_NULL) -#define IO_OBJECT_NULL ((io_object_t) 0) -#endif - -typedef IOCFPlugInInterface *io_cf_plugin_ref_t; -typedef IONotificationPortRef io_notification_port_t; - -/* private structures */ -struct darwin_cached_device { - struct list_head list; - IOUSBDeviceDescriptor dev_descriptor; - UInt32 location; - UInt64 parent_session; - UInt64 session; - UInt16 address; - char sys_path[21]; - usb_device_t **device; - int open_count; - 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 { - int is_open; - CFRunLoopSourceRef cfSource; - int fds[2]; - - struct darwin_interface { - usb_interface_t **interface; - uint8_t num_endpoints; - CFRunLoopSourceRef cfSource; - uint64_t frames[256]; - uint8_t endpoint_addrs[USB_MAXENDPOINTS]; - } interfaces[USB_MAXINTERFACES]; -}; - -struct darwin_transfer_priv { - /* Isoc */ - IOUSBIsocFrame *isoc_framelist; - int num_iso_packets; - - /* Control */ - IOUSBDevRequestTO req; - - /* Bulk */ -}; - -/* structure for signaling io completion */ -struct darwin_msg_async_io_complete { - struct usbi_transfer *itransfer; - IOReturn result; - UInt32 size; -}; - -#endif diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/linux_netlink.c b/src/3rd_party-static/libusbx-1.0.16/libusb/os/linux_netlink.c deleted file mode 100644 index 3a68f69d9c..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/linux_netlink.c +++ /dev/null @@ -1,254 +0,0 @@ -/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */ -/* - * Linux usbfs backend for libusb - * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> - -#include "libusb.h" -#include "libusbi.h" -#include "linux_usbfs.h" - -#include <linux/netlink.h> -#include <linux/filter.h> - -#define KERNEL 1 - -static int linux_netlink_socket = -1; -static pthread_t libusb_linux_event_thread; - -static void *linux_netlink_event_thread_main(void *arg); - -struct sockaddr_nl snl = { .nl_family=AF_NETLINK, .nl_groups=KERNEL }; - -int linux_netlink_start_event_monitor(void) -{ - int ret; - - snl.nl_groups = KERNEL; - - linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); - if (-1 == linux_netlink_socket) { - return LIBUSB_ERROR_OTHER; - } - - ret = bind(linux_netlink_socket, (struct sockaddr *) &snl, sizeof(snl)); - if (0 != ret) { - return LIBUSB_ERROR_OTHER; - } - - /* TODO -- add authentication */ - /* setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); */ - - ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL); - if (0 != ret) { - return LIBUSB_ERROR_OTHER; - } - - return LIBUSB_SUCCESS; -} - -int linux_netlink_stop_event_monitor(void) -{ - int r; - - if (-1 == linux_netlink_socket) { - /* already closed. nothing to do */ - return LIBUSB_SUCCESS; - } - - r = close(linux_netlink_socket); - if (0 > r) { - usbi_err(NULL, "error closing netlink socket. %s", strerror(errno)); - return LIBUSB_ERROR_OTHER; - } - - pthread_cancel(libusb_linux_event_thread); - - linux_netlink_socket = -1; - - return LIBUSB_SUCCESS; -} - -static const char *netlink_message_parse (const char *buffer, size_t len, const char *key) -{ - size_t keylen = strlen(key); - size_t offset; - - for (offset = 0 ; offset < len && '\0' != buffer[offset] ; offset += strlen(buffer + offset) + 1) { - if (0 == strncmp(buffer + offset, key, keylen) && - '=' == buffer[offset + keylen]) { - return buffer + offset + keylen + 1; - } - } - - return NULL; -} - -/* parse parts of netlink message common to both libudev and the kernel */ -static int linux_netlink_parse(char *buffer, size_t len, int *detached, const char **sys_name, - uint8_t *busnum, uint8_t *devaddr) { - const char *tmp; - int i; - - errno = 0; - - *sys_name = NULL; - *detached = 0; - *busnum = 0; - *devaddr = 0; - - tmp = netlink_message_parse((const char *) buffer, len, "ACTION"); - if (tmp == NULL) - return -1; - if (0 == strcmp(tmp, "remove")) { - *detached = 1; - } else if (0 != strcmp(tmp, "add")) { - usbi_dbg("unknown device action %s", tmp); - return -1; - } - - /* check that this is a usb message */ - tmp = netlink_message_parse(buffer, len, "SUBSYSTEM"); - if (NULL == tmp || 0 != strcmp(tmp, "usb")) { - /* not usb. ignore */ - return -1; - } - - tmp = netlink_message_parse(buffer, len, "BUSNUM"); - if (NULL == tmp) { - /* no bus number (likely a usb interface). ignore*/ - return -1; - } - - *busnum = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff); - if (errno) { - errno = 0; - return -1; - } - - tmp = netlink_message_parse(buffer, len, "DEVNUM"); - if (NULL == tmp) { - return -1; - } - - *devaddr = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff); - if (errno) { - errno = 0; - return -1; - } - - tmp = netlink_message_parse(buffer, len, "DEVPATH"); - if (NULL == tmp) { - return -1; - } - - for (i = strlen(tmp) - 1 ; i ; --i) { - if ('/' ==tmp[i]) { - *sys_name = tmp + i + 1; - break; - } - } - - /* found a usb device */ - return 0; -} - -static int linux_netlink_read_message(void) -{ - unsigned char buffer[1024]; - struct iovec iov = {.iov_base = buffer, .iov_len = sizeof(buffer)}; - struct msghdr meh = { .msg_iov=&iov, .msg_iovlen=1, - .msg_name=&snl, .msg_namelen=sizeof(snl) }; - const char *sys_name = NULL; - uint8_t busnum, devaddr; - int detached, r; - size_t len; - - /* 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; - } - - /* TODO -- authenticate this message is from the kernel or udevd */ - - r = linux_netlink_parse(buffer, len, &detached, &sys_name, - &busnum, &devaddr); - if (r) - return r; - - usbi_dbg("netlink hotplug found device busnum: %hhu, devaddr: %hhu, sys_name: %s, removed: %s", - busnum, devaddr, sys_name, detached ? "yes" : "no"); - - /* signal device is available (or not) to all contexts */ - if (detached) - linux_hotplug_disconnected(busnum, devaddr, sys_name); - else - linux_hotplug_enumerate(busnum, devaddr, sys_name); - - return 0; -} - -static void *linux_netlink_event_thread_main(void *arg) -{ - struct pollfd fds = {.fd = linux_netlink_socket, - .events = POLLIN}; - - /* silence compiler warning */ - (void) arg; - - while (1 == poll(&fds, 1, -1)) { - if (POLLIN != fds.revents) { - break; - } - - usbi_mutex_static_lock(&linux_hotplug_lock); - linux_netlink_read_message(); - usbi_mutex_static_unlock(&linux_hotplug_lock); - } - - 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); -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/linux_udev.c b/src/3rd_party-static/libusbx-1.0.16/libusb/os/linux_udev.c deleted file mode 100644 index 5a2aadfd44..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/linux_udev.c +++ /dev/null @@ -1,273 +0,0 @@ -/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */ -/* - * Linux usbfs backend for libusb - * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * Copyright (c) 2012-2013 Nathan Hjelm <hjelmn@mac.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include <assert.h> -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/utsname.h> -#include <sys/socket.h> -#include <unistd.h> -#include <libudev.h> - -#include "libusb.h" -#include "libusbi.h" -#include "linux_usbfs.h" - -/* udev context */ -static struct udev *udev_ctx = NULL; -static int udev_monitor_fd = -1; -static struct udev_monitor *udev_monitor = NULL; -static pthread_t linux_event_thread; - -static void udev_hotplug_event(struct udev_device* udev_dev); -static void *linux_udev_event_thread_main(void *arg); - -int linux_udev_start_event_monitor(void) -{ - int r; - - 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; - } - - 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; - } - - 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; - } - - 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_free_monitor; - } - - return LIBUSB_SUCCESS; - -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) -{ - assert(udev_ctx != NULL); - assert(udev_monitor != NULL); - assert(udev_monitor_fd != -1); - - /* Cancel the event thread. This is the only way to guarantee the - thread exits since closing the monitor fd won't necessarily cause - poll to return. */ - pthread_cancel(linux_event_thread); - pthread_join(linux_event_thread, NULL); - - /* Release the udev monitor */ - udev_monitor_unref(udev_monitor); - udev_monitor = NULL; - udev_monitor_fd = -1; - - /* Clean up the udev context */ - udev_unref(udev_ctx); - udev_ctx = NULL; - - return LIBUSB_SUCCESS; -} - -static void *linux_udev_event_thread_main(void *arg) -{ - struct udev_device* udev_dev; - struct pollfd fds = {.fd = udev_monitor_fd, - .events = POLLIN}; - - usbi_dbg("udev event thread entering."); - - while (1 == poll(&fds, 1, -1)) { - if (NULL == udev_monitor || POLLIN != fds.revents) { - break; - } - - 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"); - - return NULL; -} - -static int udev_device_info(struct libusb_context *ctx, int detached, - struct udev_device *udev_dev, uint8_t *busnum, - uint8_t *devaddr, const char **sys_name) { - const char *dev_node; - - dev_node = udev_device_get_devnode(udev_dev); - if (!dev_node) { - return LIBUSB_ERROR_OTHER; - } - - *sys_name = udev_device_get_sysname(udev_dev); - if (!*sys_name) { - return LIBUSB_ERROR_OTHER; - } - - return linux_get_device_address(ctx, detached, busnum, devaddr, - dev_node, *sys_name); -} - -static void udev_hotplug_event(struct udev_device* udev_dev) -{ - const char* udev_action; - const char* sys_name = NULL; - uint8_t busnum = 0, devaddr = 0; - int detached; - int r; - - do { - udev_action = udev_device_get_action(udev_dev); - if (!udev_action) { - break; - } - - detached = !strncmp(udev_action, "remove", 6); - - r = udev_device_info(NULL, detached, udev_dev, &busnum, &devaddr, &sys_name); - if (LIBUSB_SUCCESS != r) { - break; - } - - usbi_dbg("udev hotplug event. action: %s.", udev_action); - - if (strncmp(udev_action, "add", 3) == 0) { - linux_hotplug_enumerate(busnum, devaddr, sys_name); - } else if (detached) { - linux_hotplug_disconnected(busnum, devaddr, sys_name); - } else { - usbi_err(NULL, "ignoring udev action %s", udev_action); - } - } while (0); - - udev_device_unref(udev_dev); -} - -int linux_udev_scan_devices(struct libusb_context *ctx) -{ - struct udev_enumerate *enumerator; - struct udev_list_entry *devices, *entry; - struct udev_device *udev_dev; - const char *sys_name; - int r; - - assert(udev_ctx != NULL); - - enumerator = udev_enumerate_new(udev_ctx); - if (NULL == enumerator) { - usbi_err(ctx, "error creating udev enumerator"); - return LIBUSB_ERROR_OTHER; - } - - udev_enumerate_add_match_subsystem(enumerator, "usb"); - udev_enumerate_scan_devices(enumerator); - devices = udev_enumerate_get_list_entry(enumerator); - - udev_list_entry_foreach(entry, devices) { - const char *path = udev_list_entry_get_name(entry); - uint8_t busnum = 0, devaddr = 0; - - udev_dev = udev_device_new_from_syspath(udev_ctx, path); - - r = udev_device_info(ctx, 0, udev_dev, &busnum, &devaddr, &sys_name); - if (r) { - udev_device_unref(udev_dev); - continue; - } - - linux_enumerate_device(ctx, busnum, devaddr, sys_name); - udev_device_unref(udev_dev); - } - - udev_enumerate_unref(enumerator); - - return LIBUSB_SUCCESS; -} - -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); -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/linux_usbfs.c b/src/3rd_party-static/libusbx-1.0.16/libusb/os/linux_usbfs.c deleted file mode 100644 index 09288af719..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/linux_usbfs.c +++ /dev/null @@ -1,2568 +0,0 @@ -/* - * Linux usbfs backend for libusbx - * Copyright © 2007-2009 Daniel Drake <dsd@gentoo.org> - * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com> - * Copyright © 2013 Nathan Hjelm <hjelmn@mac.com> - * Copyright © 2012-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 <assert.h> -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/utsname.h> -#include <unistd.h> - -#include "libusb.h" -#include "libusbi.h" -#include "linux_usbfs.h" - -/* sysfs vs usbfs: - * opening a usbfs node causes the device to be resumed, so we attempt to - * avoid this during enumeration. - * - * sysfs allows us to read the kernel's in-memory copies of device descriptors - * and so forth, avoiding the need to open the device: - * - The binary "descriptors" file contains all config descriptors since - * 2.6.26, commit 217a9081d8e69026186067711131b77f0ce219ed - * - The binary "descriptors" file was added in 2.6.23, commit - * 69d42a78f935d19384d1f6e4f94b65bb162b36df, but it only contains the - * active config descriptors - * - The "busnum" file was added in 2.6.22, commit - * 83f7d958eab2fbc6b159ee92bf1493924e1d0f72 - * - The "devnum" file has been present since pre-2.6.18 - * - the "bConfigurationValue" file has been present since pre-2.6.18 - * - * If we have bConfigurationValue, busnum, and devnum, then we can determine - * the active configuration without having to open the usbfs node in RDWR mode. - * The busnum file is important as that is the only way we can relate sysfs - * devices to usbfs nodes. - * - * If we also have all descriptors, we can obtain the device descriptor and - * configuration without touching usbfs at all. - */ - -/* endianness for multi-byte fields: - * - * Descriptors exposed by usbfs have the multi-byte fields in the device - * descriptor as host endian. Multi-byte fields in the other descriptors are - * bus-endian. The kernel documentation says otherwise, but it is wrong. - * - * In sysfs all descriptors are bus-endian. - */ - -static const char *usbfs_path = NULL; - -/* use usbdev*.* device names in /dev instead of the usbfs bus directories */ -static int usbdev_names = 0; - -/* Linux 2.6.32 adds support for a bulk continuation URB flag. this basically - * allows us to mark URBs as being part of a specific logical transfer when - * we submit them to the kernel. then, on any error except a cancellation, all - * URBs within that transfer will be cancelled and no more URBs will be - * accepted for the transfer, meaning that no more data can creep in. - * - * The BULK_CONTINUATION flag must be set on all URBs within a bulk transfer - * (in either direction) except the first. - * For IN transfers, we must also set SHORT_NOT_OK on all URBs except the - * last; it means that the kernel should treat a short reply as an error. - * For OUT transfers, SHORT_NOT_OK must not be set. it isn't needed (OUT - * transfers can't be short unless there's already some sort of error), and - * setting this flag is disallowed (a kernel with USB debugging enabled will - * reject such URBs). - */ -static int supports_flag_bulk_continuation = -1; - -/* Linux 2.6.31 fixes support for the zero length packet URB flag. This - * allows us to mark URBs that should be followed by a zero length data - * packet, which can be required by device- or class-specific protocols. - */ -static int supports_flag_zero_packet = -1; - -/* clock ID for monotonic clock, as not all clock sources are available on all - * systems. appropriate choice made at initialization time. */ -static clockid_t monotonic_clkid = -1; - -/* Linux 2.6.22 (commit 83f7d958eab2fbc6b159ee92bf1493924e1d0f72) adds a busnum - * to sysfs, so we can relate devices. This also implies that we can read - * the active configuration through bConfigurationValue */ -static int sysfs_can_relate_devices = -1; - -/* Linux 2.6.26 (commit 217a9081d8e69026186067711131b77f0ce219ed) adds all - * config descriptors (rather then just the active config) to the sysfs - * descriptors file, so from then on we can use them. */ -static int sysfs_has_descriptors = -1; - -/* how many times have we initted (and not exited) ? */ -static volatile int init_count = 0; - -/* Serialize hotplug start/stop, scan-devices, event-thread, and poll */ -usbi_mutex_static_t linux_hotplug_lock = USBI_MUTEX_INITIALIZER; - -static int linux_start_event_monitor(void); -static int linux_stop_event_monitor(void); -static int linux_scan_devices(struct libusb_context *ctx); -static int sysfs_scan_device(struct libusb_context *ctx, const char *devname); -static int detach_kernel_driver_and_claim(struct libusb_device_handle *, int); - -#if !defined(USE_UDEV) -static int linux_default_scan_devices (struct libusb_context *ctx); -#endif - -struct linux_device_priv { - char *sysfs_dir; - unsigned char *descriptors; - int descriptors_len; - int active_config; /* cache val for !sysfs_can_relate_devices */ -}; - -struct linux_device_handle_priv { - int fd; - uint32_t caps; -}; - -enum reap_action { - NORMAL = 0, - /* submission failed after the first URB, so await cancellation/completion - * of all the others */ - SUBMIT_FAILED, - - /* cancelled by user or timeout */ - CANCELLED, - - /* completed multi-URB transfer in non-final URB */ - COMPLETED_EARLY, - - /* one or more urbs encountered a low-level error */ - ERROR, -}; - -struct linux_transfer_priv { - union { - struct usbfs_urb *urbs; - struct usbfs_urb **iso_urbs; - }; - - enum reap_action reap_action; - int num_urbs; - int num_retired; - enum libusb_transfer_status reap_status; - - /* next iso packet in user-supplied transfer to be populated */ - int iso_packet_offset; -}; - -static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent) -{ - struct libusb_context *ctx = DEVICE_CTX(dev); - char path[PATH_MAX]; - int fd; - - if (usbdev_names) - snprintf(path, PATH_MAX, "%s/usbdev%d.%d", - usbfs_path, dev->bus_number, dev->device_address); - else - snprintf(path, PATH_MAX, "%s/%03d/%03d", - usbfs_path, dev->bus_number, dev->device_address); - - fd = open(path, mode); - if (fd != -1) - return fd; /* Success */ - - if (!silent) { - usbi_err(ctx, "libusbx couldn't open USB device %s: %s", - path, strerror(errno)); - if (errno == EACCES && mode == O_RDWR) - usbi_err(ctx, "libusbx requires write access to USB " - "device nodes."); - } - - if (errno == EACCES) - return LIBUSB_ERROR_ACCESS; - if (errno == ENOENT) - return LIBUSB_ERROR_NO_DEVICE; - return LIBUSB_ERROR_IO; -} - -static struct linux_device_priv *_device_priv(struct libusb_device *dev) -{ - return (struct linux_device_priv *) dev->os_priv; -} - -static struct linux_device_handle_priv *_device_handle_priv( - struct libusb_device_handle *handle) -{ - return (struct linux_device_handle_priv *) handle->os_priv; -} - -/* check dirent for a /dev/usbdev%d.%d name - * optionally return bus/device on success */ -static int _is_usbdev_entry(struct dirent *entry, int *bus_p, int *dev_p) -{ - int busnum, devnum; - - if (sscanf(entry->d_name, "usbdev%d.%d", &busnum, &devnum) != 2) - return 0; - - usbi_dbg("found: %s", entry->d_name); - if (bus_p != NULL) - *bus_p = busnum; - if (dev_p != NULL) - *dev_p = devnum; - return 1; -} - -static int check_usb_vfs(const char *dirname) -{ - DIR *dir; - struct dirent *entry; - int found = 0; - - dir = opendir(dirname); - if (!dir) - return 0; - - while ((entry = readdir(dir)) != NULL) { - if (entry->d_name[0] == '.') - continue; - - /* We assume if we find any files that it must be the right place */ - found = 1; - break; - } - - closedir(dir); - return found; -} - -static const char *find_usbfs_path(void) -{ - const char *path = "/dev/bus/usb"; - const char *ret = NULL; - - if (check_usb_vfs(path)) { - ret = path; - } else { - path = "/proc/bus/usb"; - if (check_usb_vfs(path)) - ret = path; - } - - /* look for /dev/usbdev*.* if the normal places fail */ - if (ret == NULL) { - struct dirent *entry; - DIR *dir; - - path = "/dev"; - dir = opendir(path); - if (dir != NULL) { - while ((entry = readdir(dir)) != NULL) { - if (_is_usbdev_entry(entry, NULL, NULL)) { - /* found one; that's enough */ - ret = path; - usbdev_names = 1; - break; - } - } - closedir(dir); - } - } - - if (ret != NULL) - usbi_dbg("found usbfs at %s", ret); - - return ret; -} - -/* the monotonic clock is not usable on all systems (e.g. embedded ones often - * seem to lack it). fall back to REALTIME if we have to. */ -static clockid_t find_monotonic_clock(void) -{ -#ifdef CLOCK_MONOTONIC - struct timespec ts; - int r; - - /* Linux 2.6.28 adds CLOCK_MONOTONIC_RAW but we don't use it - * because it's not available through timerfd */ - r = clock_gettime(CLOCK_MONOTONIC, &ts); - if (r == 0) - return CLOCK_MONOTONIC; - usbi_dbg("monotonic clock doesn't work, errno %d", errno); -#endif - - return CLOCK_REALTIME; -} - -static int kernel_version_ge(int major, int minor, int sublevel) -{ - struct utsname uts; - int atoms, kmajor, kminor, ksublevel; - - if (uname(&uts) < 0) - return -1; - atoms = sscanf(uts.release, "%d.%d.%d", &kmajor, &kminor, &ksublevel); - if (atoms < 1) - return -1; - - if (kmajor > major) - return 1; - if (kmajor < major) - return 0; - - /* kmajor == major */ - if (atoms < 2) - return 0 == minor && 0 == sublevel; - if (kminor > minor) - return 1; - if (kminor < minor) - return 0; - - /* kminor == minor */ - if (atoms < 3) - return 0 == sublevel; - - return ksublevel >= sublevel; -} - -static int op_init(struct libusb_context *ctx) -{ - struct stat statbuf; - int r; - - usbfs_path = find_usbfs_path(); - if (!usbfs_path) { - usbi_err(ctx, "could not find usbfs"); - return LIBUSB_ERROR_OTHER; - } - - if (monotonic_clkid == -1) - monotonic_clkid = find_monotonic_clock(); - - if (supports_flag_bulk_continuation == -1) { - /* bulk continuation URB flag available from Linux 2.6.32 */ - supports_flag_bulk_continuation = kernel_version_ge(2,6,32); - if (supports_flag_bulk_continuation == -1) { - usbi_err(ctx, "error checking for bulk continuation support"); - return LIBUSB_ERROR_OTHER; - } - } - - if (supports_flag_bulk_continuation) - usbi_dbg("bulk continuation flag supported"); - - if (-1 == supports_flag_zero_packet) { - /* zero length packet URB flag fixed since Linux 2.6.31 */ - supports_flag_zero_packet = kernel_version_ge(2,6,31); - if (-1 == supports_flag_zero_packet) { - usbi_err(ctx, "error checking for zero length packet support"); - return LIBUSB_ERROR_OTHER; - } - } - - if (supports_flag_zero_packet) - usbi_dbg("zero length packet flag supported"); - - if (-1 == sysfs_has_descriptors) { - /* sysfs descriptors has all descriptors since Linux 2.6.26 */ - sysfs_has_descriptors = kernel_version_ge(2,6,26); - if (-1 == sysfs_has_descriptors) { - usbi_err(ctx, "error checking for sysfs descriptors"); - return LIBUSB_ERROR_OTHER; - } - } - - if (-1 == sysfs_can_relate_devices) { - /* sysfs has busnum since Linux 2.6.22 */ - sysfs_can_relate_devices = kernel_version_ge(2,6,22); - if (-1 == sysfs_can_relate_devices) { - usbi_err(ctx, "error checking for sysfs busnum"); - return LIBUSB_ERROR_OTHER; - } - } - - if (sysfs_can_relate_devices || sysfs_has_descriptors) { - r = stat(SYSFS_DEVICE_PATH, &statbuf); - if (r != 0 || !S_ISDIR(statbuf.st_mode)) { - usbi_warn(ctx, "sysfs not mounted"); - sysfs_can_relate_devices = 0; - sysfs_has_descriptors = 0; - } - } - - if (sysfs_can_relate_devices) - usbi_dbg("sysfs can relate devices"); - - if (sysfs_has_descriptors) - usbi_dbg("sysfs has complete descriptors"); - - usbi_mutex_static_lock(&linux_hotplug_lock); - r = LIBUSB_SUCCESS; - if (init_count == 0) { - /* start up hotplug event handler */ - r = linux_start_event_monitor(); - } - if (r == LIBUSB_SUCCESS) { - r = linux_scan_devices(ctx); - if (r == LIBUSB_SUCCESS) - init_count++; - else if (init_count == 0) - linux_stop_event_monitor(); - } else - usbi_err(ctx, "error starting hotplug event monitor"); - usbi_mutex_static_unlock(&linux_hotplug_lock); - - return r; -} - -static void op_exit(void) -{ - usbi_mutex_static_lock(&linux_hotplug_lock); - assert(init_count != 0); - if (!--init_count) { - /* tear down event handler */ - (void)linux_stop_event_monitor(); - } - usbi_mutex_static_unlock(&linux_hotplug_lock); -} - -static int linux_start_event_monitor(void) -{ -#if defined(USE_UDEV) - return linux_udev_start_event_monitor(); -#else - return linux_netlink_start_event_monitor(); -#endif -} - -static int linux_stop_event_monitor(void) -{ -#if defined(USE_UDEV) - return linux_udev_stop_event_monitor(); -#else - return linux_netlink_stop_event_monitor(); -#endif -} - -static int linux_scan_devices(struct libusb_context *ctx) -{ -#if defined(USE_UDEV) - return linux_udev_scan_devices(ctx); -#else - return linux_default_scan_devices(ctx); -#endif -} - -static void op_hotplug_poll(void) -{ -#if defined(USE_UDEV) - linux_udev_hotplug_poll(); -#else - linux_netlink_hotplug_poll(); -#endif -} - -static int _open_sysfs_attr(struct libusb_device *dev, const char *attr) -{ - struct linux_device_priv *priv = _device_priv(dev); - char filename[PATH_MAX]; - int fd; - - snprintf(filename, PATH_MAX, "%s/%s/%s", - SYSFS_DEVICE_PATH, priv->sysfs_dir, attr); - fd = open(filename, O_RDONLY); - if (fd < 0) { - usbi_err(DEVICE_CTX(dev), - "open %s failed ret=%d errno=%d", filename, fd, errno); - return LIBUSB_ERROR_IO; - } - - return fd; -} - -/* Note only suitable for attributes which always read >= 0, < 0 is error */ -static int __read_sysfs_attr(struct libusb_context *ctx, - const char *devname, const char *attr) -{ - char filename[PATH_MAX]; - FILE *f; - int r, value; - - snprintf(filename, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH, - devname, attr); - f = fopen(filename, "r"); - if (f == NULL) { - if (errno == ENOENT) { - /* File doesn't exist. Assume the device has been - disconnected (see trac ticket #70). */ - return LIBUSB_ERROR_NO_DEVICE; - } - usbi_err(ctx, "open %s failed errno=%d", filename, errno); - return LIBUSB_ERROR_IO; - } - - r = fscanf(f, "%d", &value); - fclose(f); - if (r != 1) { - usbi_err(ctx, "fscanf %s returned %d, errno=%d", attr, r, errno); - return LIBUSB_ERROR_NO_DEVICE; /* For unplug race (trac #70) */ - } - if (value < 0) { - usbi_err(ctx, "%s contains a negative value", filename); - return LIBUSB_ERROR_IO; - } - - return value; -} - -static int op_get_device_descriptor(struct libusb_device *dev, - unsigned char *buffer, int *host_endian) -{ - struct linux_device_priv *priv = _device_priv(dev); - - *host_endian = sysfs_has_descriptors ? 0 : 1; - memcpy(buffer, priv->descriptors, DEVICE_DESC_LENGTH); - - return 0; -} - -/* read the bConfigurationValue for a device */ -static int sysfs_get_active_config(struct libusb_device *dev, int *config) -{ - char *endptr; - char tmp[4] = {0, 0, 0, 0}; - long num; - int fd; - ssize_t r; - - fd = _open_sysfs_attr(dev, "bConfigurationValue"); - if (fd < 0) - return fd; - - r = read(fd, tmp, sizeof(tmp)); - close(fd); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), - "read bConfigurationValue failed ret=%d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } else if (r == 0) { - usbi_dbg("device unconfigured"); - *config = -1; - return 0; - } - - if (tmp[sizeof(tmp) - 1] != 0) { - usbi_err(DEVICE_CTX(dev), "not null-terminated?"); - return LIBUSB_ERROR_IO; - } else if (tmp[0] == 0) { - usbi_err(DEVICE_CTX(dev), "no configuration value?"); - return LIBUSB_ERROR_IO; - } - - num = strtol(tmp, &endptr, 10); - if (endptr == tmp) { - usbi_err(DEVICE_CTX(dev), "error converting '%s' to integer", tmp); - return LIBUSB_ERROR_IO; - } - - *config = (int) num; - return 0; -} - -int linux_get_device_address (struct libusb_context *ctx, int detached, - uint8_t *busnum, uint8_t *devaddr,const char *dev_node, - const char *sys_name) -{ - usbi_dbg("getting address for device: %s detached: %d", sys_name, detached); - /* can't use sysfs to read the bus and device number if the - * device has been detached */ - if (!sysfs_can_relate_devices || detached || NULL == sys_name) { - if (NULL == dev_node) { - return LIBUSB_ERROR_OTHER; - } - - /* will this work with all supported kernel versions? */ - if (!strncmp(dev_node, "/dev/bus/usb", 12)) { - sscanf (dev_node, "/dev/bus/usb/%hhd/%hhd", busnum, devaddr); - } else if (!strncmp(dev_node, "/proc/bus/usb", 13)) { - sscanf (dev_node, "/proc/bus/usb/%hhd/%hhd", busnum, devaddr); - } - - return LIBUSB_SUCCESS; - } - - usbi_dbg("scan %s", sys_name); - - *busnum = __read_sysfs_attr(ctx, sys_name, "busnum"); - if (0 > *busnum) - return *busnum; - - *devaddr = __read_sysfs_attr(ctx, sys_name, "devnum"); - if (0 > *devaddr) - return *devaddr; - - usbi_dbg("bus=%d dev=%d", *busnum, *devaddr); - if (*busnum > 255 || *devaddr > 255) - return LIBUSB_ERROR_INVALID_PARAM; - - return LIBUSB_SUCCESS; -} - -/* Return offset of the next descriptor with the given type */ -static int seek_to_next_descriptor(struct libusb_context *ctx, - uint8_t descriptor_type, unsigned char *buffer, int size) -{ - struct usb_descriptor_header header; - int i; - - for (i = 0; size >= 0; i += header.bLength, size -= header.bLength) { - if (size == 0) - return LIBUSB_ERROR_NOT_FOUND; - - if (size < 2) { - usbi_err(ctx, "short descriptor read %d/2", size); - return LIBUSB_ERROR_IO; - } - usbi_parse_descriptor(buffer + i, "bb", &header, 0); - - if (i && header.bDescriptorType == descriptor_type) - return i; - } - usbi_err(ctx, "bLength overflow by %d bytes", -size); - return LIBUSB_ERROR_IO; -} - -/* Return offset to next config */ -static int seek_to_next_config(struct libusb_context *ctx, - unsigned char *buffer, int size) -{ - struct libusb_config_descriptor config; - - if (size == 0) - return LIBUSB_ERROR_NOT_FOUND; - - if (size < LIBUSB_DT_CONFIG_SIZE) { - usbi_err(ctx, "short descriptor read %d/%d", - size, LIBUSB_DT_CONFIG_SIZE); - return LIBUSB_ERROR_IO; - } - - usbi_parse_descriptor(buffer, "bbwbbbbb", &config, 0); - if (config.bDescriptorType != LIBUSB_DT_CONFIG) { - usbi_err(ctx, "descriptor is not a config desc (type 0x%02x)", - config.bDescriptorType); - return LIBUSB_ERROR_IO; - } - - /* - * In usbfs the config descriptors are config.wTotalLength bytes apart, - * with any short reads from the device appearing as holes in the file. - * - * In sysfs wTotalLength is ignored, instead the kernel returns a - * config descriptor with verified bLength fields, with descriptors - * with an invalid bLength removed. - */ - if (sysfs_has_descriptors) { - int next = seek_to_next_descriptor(ctx, LIBUSB_DT_CONFIG, - buffer, size); - if (next == LIBUSB_ERROR_NOT_FOUND) - next = size; - if (next < 0) - return next; - - if (next != config.wTotalLength) - usbi_warn(ctx, "config length mismatch wTotalLength " - "%d real %d", config.wTotalLength, next); - return next; - } else { - if (config.wTotalLength < LIBUSB_DT_CONFIG_SIZE) { - usbi_err(ctx, "invalid wTotalLength %d", - config.wTotalLength); - return LIBUSB_ERROR_IO; - } else if (config.wTotalLength > size) { - usbi_warn(ctx, "short descriptor read %d/%d", - size, config.wTotalLength); - return size; - } else - return config.wTotalLength; - } -} - -static int op_get_config_descriptor_by_value(struct libusb_device *dev, - uint8_t value, unsigned char **buffer, int *host_endian) -{ - struct libusb_context *ctx = DEVICE_CTX(dev); - struct linux_device_priv *priv = _device_priv(dev); - unsigned char *descriptors = priv->descriptors; - int size = priv->descriptors_len; - struct libusb_config_descriptor *config; - - *buffer = NULL; - /* Unlike the device desc. config descs. are always in raw format */ - *host_endian = 0; - - /* Skip device header */ - descriptors += DEVICE_DESC_LENGTH; - size -= DEVICE_DESC_LENGTH; - - /* Seek till the config is found, or till "EOF" */ - while (1) { - int next = seek_to_next_config(ctx, descriptors, size); - if (next < 0) - return next; - config = (struct libusb_config_descriptor *)descriptors; - if (config->bConfigurationValue == value) { - *buffer = descriptors; - return next; - } - size -= next; - descriptors += next; - } -} - -static int op_get_active_config_descriptor(struct libusb_device *dev, - unsigned char *buffer, size_t len, int *host_endian) -{ - int r, config; - unsigned char *config_desc; - - if (sysfs_can_relate_devices) { - r = sysfs_get_active_config(dev, &config); - if (r < 0) - return r; - } else { - /* Use cached bConfigurationValue */ - struct linux_device_priv *priv = _device_priv(dev); - config = priv->active_config; - } - if (config == -1) - return LIBUSB_ERROR_NOT_FOUND; - - r = op_get_config_descriptor_by_value(dev, config, &config_desc, - host_endian); - if (r < 0) - return r; - - len = MIN(len, r); - memcpy(buffer, config_desc, len); - return len; -} - -static int op_get_config_descriptor(struct libusb_device *dev, - uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) -{ - struct linux_device_priv *priv = _device_priv(dev); - unsigned char *descriptors = priv->descriptors; - int i, r, size = priv->descriptors_len; - - /* Unlike the device desc. config descs. are always in raw format */ - *host_endian = 0; - - /* Skip device header */ - descriptors += DEVICE_DESC_LENGTH; - size -= DEVICE_DESC_LENGTH; - - /* Seek till the config is found, or till "EOF" */ - for (i = 0; ; i++) { - r = seek_to_next_config(DEVICE_CTX(dev), descriptors, size); - if (r < 0) - return r; - if (i == config_index) - break; - size -= r; - descriptors += r; - } - - len = MIN(len, r); - memcpy(buffer, descriptors, len); - return len; -} - -/* send a control message to retrieve active configuration */ -static int usbfs_get_active_config(struct libusb_device *dev, int fd) -{ - unsigned char active_config = 0; - int r; - - struct usbfs_ctrltransfer ctrl = { - .bmRequestType = LIBUSB_ENDPOINT_IN, - .bRequest = LIBUSB_REQUEST_GET_CONFIGURATION, - .wValue = 0, - .wIndex = 0, - .wLength = 1, - .timeout = 1000, - .data = &active_config - }; - - r = ioctl(fd, IOCTL_USBFS_CONTROL, &ctrl); - if (r < 0) { - if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - /* we hit this error path frequently with buggy devices :( */ - usbi_warn(DEVICE_CTX(dev), - "get_configuration failed ret=%d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } - - return active_config; -} - -static int initialize_device(struct libusb_device *dev, uint8_t busnum, - uint8_t devaddr, const char *sysfs_dir) -{ - struct linux_device_priv *priv = _device_priv(dev); - struct libusb_context *ctx = DEVICE_CTX(dev); - int descriptors_size = 512; /* Begin with a 1024 byte alloc */ - int fd, speed; - ssize_t r; - - dev->bus_number = busnum; - dev->device_address = devaddr; - - if (sysfs_dir) { - priv->sysfs_dir = malloc(strlen(sysfs_dir) + 1); - if (!priv->sysfs_dir) - return LIBUSB_ERROR_NO_MEM; - strcpy(priv->sysfs_dir, sysfs_dir); - - /* Note speed can contain 1.5, in this case __read_sysfs_attr - will stop parsing at the '.' and return 1 */ - speed = __read_sysfs_attr(DEVICE_CTX(dev), sysfs_dir, "speed"); - if (speed >= 0) { - switch (speed) { - case 1: dev->speed = LIBUSB_SPEED_LOW; break; - case 12: dev->speed = LIBUSB_SPEED_FULL; break; - case 480: dev->speed = LIBUSB_SPEED_HIGH; break; - case 5000: dev->speed = LIBUSB_SPEED_SUPER; break; - default: - usbi_warn(DEVICE_CTX(dev), "Unknown device speed: %d Mbps", speed); - } - } - } - - /* cache descriptors in memory */ - if (sysfs_has_descriptors) - fd = _open_sysfs_attr(dev, "descriptors"); - else - fd = _get_usbfs_fd(dev, O_RDONLY, 0); - if (fd < 0) - return fd; - - do { - descriptors_size *= 2; - priv->descriptors = usbi_reallocf(priv->descriptors, - descriptors_size); - if (!priv->descriptors) { - close(fd); - return LIBUSB_ERROR_NO_MEM; - } - /* usbfs has holes in the file */ - if (!sysfs_has_descriptors) { - memset(priv->descriptors + priv->descriptors_len, - 0, descriptors_size - priv->descriptors_len); - } - r = read(fd, priv->descriptors + priv->descriptors_len, - descriptors_size - priv->descriptors_len); - if (r < 0) { - usbi_err(ctx, "read descriptor failed ret=%d errno=%d", - fd, errno); - close(fd); - return LIBUSB_ERROR_IO; - } - priv->descriptors_len += r; - } while (priv->descriptors_len == descriptors_size); - - close(fd); - - if (priv->descriptors_len < DEVICE_DESC_LENGTH) { - usbi_err(ctx, "short descriptor read (%d)", - priv->descriptors_len); - return LIBUSB_ERROR_IO; - } - - if (sysfs_can_relate_devices) - return LIBUSB_SUCCESS; - - /* cache active config */ - fd = _get_usbfs_fd(dev, O_RDWR, 1); - if (fd < 0) { - /* cannot send a control message to determine the active - * config. just assume the first one is active. */ - usbi_warn(ctx, "Missing rw usbfs access; cannot determine " - "active configuration descriptor"); - if (priv->descriptors_len >= - (DEVICE_DESC_LENGTH + LIBUSB_DT_CONFIG_SIZE)) { - struct libusb_config_descriptor config; - usbi_parse_descriptor( - priv->descriptors + DEVICE_DESC_LENGTH, - "bbwbbbbb", &config, 0); - priv->active_config = config.bConfigurationValue; - } else - priv->active_config = -1; /* No config dt */ - - return LIBUSB_SUCCESS; - } - - r = usbfs_get_active_config(dev, fd); - if (r > 0) { - priv->active_config = r; - r = LIBUSB_SUCCESS; - } else if (r == 0) { - /* some buggy devices have a configuration 0, but we're - * reaching into the corner of a corner case here, so let's - * not support buggy devices in these circumstances. - * stick to the specs: a configuration value of 0 means - * unconfigured. */ - usbi_dbg("active cfg 0? assuming unconfigured device"); - priv->active_config = -1; - r = LIBUSB_SUCCESS; - } else if (r == LIBUSB_ERROR_IO) { - /* buggy devices sometimes fail to report their active config. - * assume unconfigured and continue the probing */ - usbi_warn(ctx, "couldn't query active configuration, assuming" - " unconfigured"); - priv->active_config = -1; - r = LIBUSB_SUCCESS; - } /* else r < 0, just return the error code */ - - close(fd); - return r; -} - -static int linux_get_parent_info(struct libusb_device *dev, const char *sysfs_dir) -{ - struct libusb_context *ctx = DEVICE_CTX(dev); - struct libusb_device *it; - char *parent_sysfs_dir, *tmp; - int ret, add_parent = 1; - - /* XXX -- can we figure out the topology when using usbfs? */ - if (NULL == sysfs_dir || 0 == strncmp(sysfs_dir, "usb", 3)) { - /* either using usbfs or finding the parent of a root hub */ - return LIBUSB_SUCCESS; - } - - parent_sysfs_dir = strdup(sysfs_dir); - if (NULL != (tmp = strrchr(parent_sysfs_dir, '.')) || - NULL != (tmp = strrchr(parent_sysfs_dir, '-'))) { - dev->port_number = atoi(tmp + 1); - *tmp = '\0'; - } else { - usbi_warn(ctx, "Can not parse sysfs_dir: %s, no parent info", - parent_sysfs_dir); - free (parent_sysfs_dir); - return LIBUSB_SUCCESS; - } - - /* is the parent a root hub? */ - if (NULL == strchr(parent_sysfs_dir, '-')) { - tmp = parent_sysfs_dir; - ret = asprintf (&parent_sysfs_dir, "usb%s", tmp); - free (tmp); - if (0 > ret) { - return LIBUSB_ERROR_NO_MEM; - } - } - -retry: - /* find the parent in the context */ - usbi_mutex_lock(&ctx->usb_devs_lock); - list_for_each_entry(it, &ctx->usb_devs, list, struct libusb_device) { - struct linux_device_priv *priv = _device_priv(it); - if (0 == strcmp (priv->sysfs_dir, parent_sysfs_dir)) { - dev->parent_dev = libusb_ref_device(it); - break; - } - } - usbi_mutex_unlock(&ctx->usb_devs_lock); - - if (!dev->parent_dev && add_parent) { - usbi_dbg("parent_dev %s not enumerated yet, enumerating now", - parent_sysfs_dir); - sysfs_scan_device(ctx, parent_sysfs_dir); - add_parent = 0; - goto retry; - } - - usbi_dbg("Dev %p (%s) has parent %p (%s) port %d", dev, sysfs_dir, - dev->parent_dev, parent_sysfs_dir, dev->port_number); - - free (parent_sysfs_dir); - - return LIBUSB_SUCCESS; -} - -int linux_enumerate_device(struct libusb_context *ctx, - uint8_t busnum, uint8_t devaddr, const char *sysfs_dir) -{ - unsigned long session_id; - struct libusb_device *dev; - int r = 0; - - /* FIXME: session ID is not guaranteed unique as addresses can wrap and - * will be reused. instead we should add a simple sysfs attribute with - * a session ID. */ - session_id = busnum << 8 | devaddr; - usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr, - session_id); - - if (usbi_get_device_by_session_id(ctx, session_id)) { - /* device already exists in the context */ - usbi_dbg("session_id %ld already exists", session_id); - return LIBUSB_SUCCESS; - } - - usbi_dbg("allocating new device for %d/%d (session %ld)", - busnum, devaddr, session_id); - dev = usbi_alloc_device(ctx, session_id); - if (!dev) - return LIBUSB_ERROR_NO_MEM; - - r = initialize_device(dev, busnum, devaddr, sysfs_dir); - if (r < 0) - goto out; - r = usbi_sanitize_device(dev); - if (r < 0) - goto out; - - r = linux_get_parent_info(dev, sysfs_dir); - if (r < 0) - goto out; -out: - if (r < 0) - libusb_unref_device(dev); - else - usbi_connect_device(dev); - - return r; -} - -void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name) -{ - struct libusb_context *ctx; - - usbi_mutex_static_lock(&active_contexts_lock); - list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) { - linux_enumerate_device(ctx, busnum, devaddr, sys_name); - } - usbi_mutex_static_unlock(&active_contexts_lock); -} - -void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name) -{ - struct libusb_context *ctx; - struct libusb_device *dev; - unsigned long session_id = busnum << 8 | devaddr; - - usbi_mutex_static_lock(&active_contexts_lock); - list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) { - dev = usbi_get_device_by_session_id (ctx, session_id); - if (NULL != dev) { - usbi_disconnect_device (dev); - } else { - usbi_dbg("device not found for session %x", session_id); - } - } - usbi_mutex_static_unlock(&active_contexts_lock); -} - -#if !defined(USE_UDEV) -/* open a bus directory and adds all discovered devices to the context */ -static int usbfs_scan_busdir(struct libusb_context *ctx, uint8_t busnum) -{ - DIR *dir; - char dirpath[PATH_MAX]; - struct dirent *entry; - int r = LIBUSB_ERROR_IO; - - snprintf(dirpath, PATH_MAX, "%s/%03d", usbfs_path, busnum); - usbi_dbg("%s", dirpath); - dir = opendir(dirpath); - if (!dir) { - usbi_err(ctx, "opendir '%s' failed, errno=%d", dirpath, errno); - /* FIXME: should handle valid race conditions like hub unplugged - * during directory iteration - this is not an error */ - return r; - } - - while ((entry = readdir(dir))) { - int devaddr; - - if (entry->d_name[0] == '.') - continue; - - devaddr = atoi(entry->d_name); - if (devaddr == 0) { - usbi_dbg("unknown dir entry %s", entry->d_name); - continue; - } - - if (linux_enumerate_device(ctx, busnum, (uint8_t) devaddr, NULL)) { - usbi_dbg("failed to enumerate dir entry %s", entry->d_name); - continue; - } - - r = 0; - } - - closedir(dir); - return r; -} - -static int usbfs_get_device_list(struct libusb_context *ctx) -{ - struct dirent *entry; - DIR *buses = opendir(usbfs_path); - int r = 0; - - if (!buses) { - usbi_err(ctx, "opendir buses failed errno=%d", errno); - return LIBUSB_ERROR_IO; - } - - while ((entry = readdir(buses))) { - int busnum; - - if (entry->d_name[0] == '.') - continue; - - if (usbdev_names) { - int devaddr; - if (!_is_usbdev_entry(entry, &busnum, &devaddr)) - continue; - - r = linux_enumerate_device(ctx, busnum, (uint8_t) devaddr, NULL); - if (r < 0) { - usbi_dbg("failed to enumerate dir entry %s", entry->d_name); - continue; - } - } else { - busnum = atoi(entry->d_name); - if (busnum == 0) { - usbi_dbg("unknown dir entry %s", entry->d_name); - continue; - } - - r = usbfs_scan_busdir(ctx, busnum); - if (r < 0) - break; - } - } - - closedir(buses); - return r; - -} -#endif - -static int sysfs_scan_device(struct libusb_context *ctx, const char *devname) -{ - uint8_t busnum, devaddr; - int ret; - - ret = linux_get_device_address (ctx, 0, &busnum, &devaddr, NULL, devname); - if (LIBUSB_SUCCESS != ret) { - return ret; - } - - return linux_enumerate_device(ctx, busnum & 0xff, devaddr & 0xff, - devname); -} - -#if !defined(USE_UDEV) -static int sysfs_get_device_list(struct libusb_context *ctx) -{ - DIR *devices = opendir(SYSFS_DEVICE_PATH); - struct dirent *entry; - int r = LIBUSB_ERROR_IO; - - if (!devices) { - usbi_err(ctx, "opendir devices failed errno=%d", errno); - return r; - } - - while ((entry = readdir(devices))) { - if ((!isdigit(entry->d_name[0]) && strncmp(entry->d_name, "usb", 3)) - || strchr(entry->d_name, ':')) - continue; - - if (sysfs_scan_device(ctx, entry->d_name)) { - usbi_dbg("failed to enumerate dir entry %s", entry->d_name); - continue; - } - - r = 0; - } - - closedir(devices); - return r; -} - -static int linux_default_scan_devices (struct libusb_context *ctx) -{ - /* we can retrieve device list and descriptors from sysfs or usbfs. - * sysfs is preferable, because if we use usbfs we end up resuming - * any autosuspended USB devices. however, sysfs is not available - * everywhere, so we need a usbfs fallback too. - * - * as described in the "sysfs vs usbfs" comment at the top of this - * file, sometimes we have sysfs but not enough information to - * relate sysfs devices to usbfs nodes. op_init() determines the - * adequacy of sysfs and sets sysfs_can_relate_devices. - */ - if (sysfs_can_relate_devices != 0) - return sysfs_get_device_list(ctx); - else - return usbfs_get_device_list(ctx); -} -#endif - -static int op_open(struct libusb_device_handle *handle) -{ - struct linux_device_handle_priv *hpriv = _device_handle_priv(handle); - int r; - - hpriv->fd = _get_usbfs_fd(handle->dev, O_RDWR, 0); - if (hpriv->fd < 0) - return hpriv->fd; - - r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps); - if (r < 0) { - if (errno == ENOTTY) - usbi_dbg("getcap not available"); - else - usbi_err(HANDLE_CTX(handle), "getcap failed (%d)", errno); - hpriv->caps = 0; - if (supports_flag_zero_packet) - hpriv->caps |= USBFS_CAP_ZERO_PACKET; - if (supports_flag_bulk_continuation) - hpriv->caps |= USBFS_CAP_BULK_CONTINUATION; - } - - return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); -} - -static void op_close(struct libusb_device_handle *dev_handle) -{ - int fd = _device_handle_priv(dev_handle)->fd; - usbi_remove_pollfd(HANDLE_CTX(dev_handle), fd); - close(fd); -} - -static int op_get_configuration(struct libusb_device_handle *handle, - int *config) -{ - int r; - - if (sysfs_can_relate_devices) { - r = sysfs_get_active_config(handle->dev, config); - } else { - r = usbfs_get_active_config(handle->dev, - _device_handle_priv(handle)->fd); - } - if (r < 0) - return r; - - if (*config == -1) { - usbi_err(HANDLE_CTX(handle), "device unconfigured"); - *config = 0; - } - - return 0; -} - -static int op_set_configuration(struct libusb_device_handle *handle, int config) -{ - struct linux_device_priv *priv = _device_priv(handle->dev); - int fd = _device_handle_priv(handle)->fd; - int r = ioctl(fd, IOCTL_USBFS_SETCONFIG, &config); - if (r) { - if (errno == EINVAL) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == EBUSY) - return LIBUSB_ERROR_BUSY; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), "failed, error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - /* update our cached active config descriptor */ - priv->active_config = config; - - return LIBUSB_SUCCESS; -} - -static int claim_interface(struct libusb_device_handle *handle, int iface) -{ - int fd = _device_handle_priv(handle)->fd; - int r = ioctl(fd, IOCTL_USBFS_CLAIMINTF, &iface); - if (r) { - if (errno == ENOENT) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == EBUSY) - return LIBUSB_ERROR_BUSY; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "claim interface failed, error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - return 0; -} - -static int release_interface(struct libusb_device_handle *handle, int iface) -{ - int fd = _device_handle_priv(handle)->fd; - int r = ioctl(fd, IOCTL_USBFS_RELEASEINTF, &iface); - if (r) { - if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "release interface failed, error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - return 0; -} - -static int op_set_interface(struct libusb_device_handle *handle, int iface, - int altsetting) -{ - int fd = _device_handle_priv(handle)->fd; - struct usbfs_setinterface setintf; - int r; - - setintf.interface = iface; - setintf.altsetting = altsetting; - r = ioctl(fd, IOCTL_USBFS_SETINTF, &setintf); - if (r) { - if (errno == EINVAL) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "setintf failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return 0; -} - -static int op_clear_halt(struct libusb_device_handle *handle, - unsigned char endpoint) -{ - int fd = _device_handle_priv(handle)->fd; - unsigned int _endpoint = endpoint; - int r = ioctl(fd, IOCTL_USBFS_CLEAR_HALT, &_endpoint); - if (r) { - if (errno == ENOENT) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "clear_halt failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return 0; -} - -static int op_reset_device(struct libusb_device_handle *handle) -{ - int fd = _device_handle_priv(handle)->fd; - int i, r, ret = 0; - - /* Doing a device reset will cause the usbfs driver to get unbound - from any interfaces it is bound to. By voluntarily unbinding - the usbfs driver ourself, we stop the kernel from rebinding - the interface after reset (which would end up with the interface - getting bound to the in kernel driver if any). */ - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (handle->claimed_interfaces & (1L << i)) { - release_interface(handle, i); - } - } - - usbi_mutex_lock(&handle->lock); - r = ioctl(fd, IOCTL_USBFS_RESET, NULL); - if (r) { - if (errno == ENODEV) { - ret = LIBUSB_ERROR_NOT_FOUND; - goto out; - } - - usbi_err(HANDLE_CTX(handle), - "reset failed error %d errno %d", r, errno); - ret = LIBUSB_ERROR_OTHER; - goto out; - } - - /* And re-claim any interfaces which were claimed before the reset */ - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (handle->claimed_interfaces & (1L << i)) { - /* - * A driver may have completed modprobing during - * IOCTL_USBFS_RESET, and bound itself as soon as - * IOCTL_USBFS_RESET released the device lock - */ - r = detach_kernel_driver_and_claim(handle, i); - if (r) { - usbi_warn(HANDLE_CTX(handle), - "failed to re-claim interface %d after reset: %s", - i, libusb_error_name(r)); - handle->claimed_interfaces &= ~(1L << i); - ret = LIBUSB_ERROR_NOT_FOUND; - } - } - } -out: - usbi_mutex_unlock(&handle->lock); - return ret; -} - -static int op_kernel_driver_active(struct libusb_device_handle *handle, - int interface) -{ - int fd = _device_handle_priv(handle)->fd; - struct usbfs_getdriver getdrv; - int r; - - getdrv.interface = interface; - r = ioctl(fd, IOCTL_USBFS_GETDRIVER, &getdrv); - if (r) { - if (errno == ENODATA) - return 0; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "get driver failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return (strcmp(getdrv.driver, "usbfs") == 0) ? 0 : 1; -} - -static int op_detach_kernel_driver(struct libusb_device_handle *handle, - int interface) -{ - int fd = _device_handle_priv(handle)->fd; - struct usbfs_ioctl command; - struct usbfs_getdriver getdrv; - int r; - - command.ifno = interface; - command.ioctl_code = IOCTL_USBFS_DISCONNECT; - command.data = NULL; - - getdrv.interface = interface; - r = ioctl(fd, IOCTL_USBFS_GETDRIVER, &getdrv); - if (r == 0 && strcmp(getdrv.driver, "usbfs") == 0) - return LIBUSB_ERROR_NOT_FOUND; - - r = ioctl(fd, IOCTL_USBFS_IOCTL, &command); - if (r) { - if (errno == ENODATA) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == EINVAL) - return LIBUSB_ERROR_INVALID_PARAM; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "detach failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return 0; -} - -static int op_attach_kernel_driver(struct libusb_device_handle *handle, - int interface) -{ - int fd = _device_handle_priv(handle)->fd; - struct usbfs_ioctl command; - int r; - - command.ifno = interface; - command.ioctl_code = IOCTL_USBFS_CONNECT; - command.data = NULL; - - r = ioctl(fd, IOCTL_USBFS_IOCTL, &command); - if (r < 0) { - if (errno == ENODATA) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == EINVAL) - return LIBUSB_ERROR_INVALID_PARAM; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - else if (errno == EBUSY) - return LIBUSB_ERROR_BUSY; - - usbi_err(HANDLE_CTX(handle), - "attach failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } else if (r == 0) { - return LIBUSB_ERROR_NOT_FOUND; - } - - return 0; -} - -static int detach_kernel_driver_and_claim(struct libusb_device_handle *handle, - int interface) -{ - struct usbfs_disconnect_claim dc; - int r, fd = _device_handle_priv(handle)->fd; - - dc.interface = interface; - strcpy(dc.driver, "usbfs"); - dc.flags = USBFS_DISCONNECT_CLAIM_EXCEPT_DRIVER; - r = ioctl(fd, IOCTL_USBFS_DISCONNECT_CLAIM, &dc); - if (r == 0 || (r != 0 && errno != ENOTTY)) { - if (r == 0) - return 0; - - switch (errno) { - case EBUSY: - return LIBUSB_ERROR_BUSY; - case EINVAL: - return LIBUSB_ERROR_INVALID_PARAM; - case ENODEV: - return LIBUSB_ERROR_NO_DEVICE; - } - usbi_err(HANDLE_CTX(handle), - "disconnect-and-claim failed errno %d", errno); - return LIBUSB_ERROR_OTHER; - } - - /* Fallback code for kernels which don't support the - disconnect-and-claim ioctl */ - r = op_detach_kernel_driver(handle, interface); - if (r != 0 && r != LIBUSB_ERROR_NOT_FOUND) - return r; - - return claim_interface(handle, interface); -} - -static int op_claim_interface(struct libusb_device_handle *handle, int iface) -{ - if (handle->auto_detach_kernel_driver) - return detach_kernel_driver_and_claim(handle, iface); - else - return claim_interface(handle, iface); -} - -static int op_release_interface(struct libusb_device_handle *handle, int iface) -{ - int r; - - r = release_interface(handle, iface); - if (r) - return r; - - if (handle->auto_detach_kernel_driver) - op_attach_kernel_driver(handle, iface); - - return 0; -} - -static void op_destroy_device(struct libusb_device *dev) -{ - struct linux_device_priv *priv = _device_priv(dev); - if (priv->descriptors) - free(priv->descriptors); - if (priv->sysfs_dir) - free(priv->sysfs_dir); -} - -/* URBs are discarded in reverse order of submission to avoid races. */ -static int discard_urbs(struct usbi_transfer *itransfer, int first, int last_plus_one) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = - usbi_transfer_get_os_priv(itransfer); - struct linux_device_handle_priv *dpriv = - _device_handle_priv(transfer->dev_handle); - int i, ret = 0; - struct usbfs_urb *urb; - - for (i = last_plus_one - 1; i >= first; i--) { - if (LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type) - urb = tpriv->iso_urbs[i]; - else - urb = &tpriv->urbs[i]; - - if (0 == ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, urb)) - continue; - - if (EINVAL == errno) { - usbi_dbg("URB not found --> assuming ready to be reaped"); - if (i == (last_plus_one - 1)) - ret = LIBUSB_ERROR_NOT_FOUND; - } else if (ENODEV == errno) { - usbi_dbg("Device not found for URB --> assuming ready to be reaped"); - ret = LIBUSB_ERROR_NO_DEVICE; - } else { - usbi_warn(TRANSFER_CTX(transfer), - "unrecognised discard errno %d", errno); - ret = LIBUSB_ERROR_OTHER; - } - } - return ret; -} - -static void free_iso_urbs(struct linux_transfer_priv *tpriv) -{ - int i; - for (i = 0; i < tpriv->num_urbs; i++) { - struct usbfs_urb *urb = tpriv->iso_urbs[i]; - if (!urb) - break; - free(urb); - } - - free(tpriv->iso_urbs); - tpriv->iso_urbs = NULL; -} - -static int submit_bulk_transfer(struct usbi_transfer *itransfer, - unsigned char urb_type) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct linux_device_handle_priv *dpriv = - _device_handle_priv(transfer->dev_handle); - struct usbfs_urb *urbs; - int is_out = (transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK) - == LIBUSB_ENDPOINT_OUT; - int bulk_buffer_len, use_bulk_continuation; - int r; - int i; - size_t alloc_size; - - if (tpriv->urbs) - return LIBUSB_ERROR_BUSY; - - if (is_out && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) && - !(dpriv->caps & USBFS_CAP_ZERO_PACKET)) - return LIBUSB_ERROR_NOT_SUPPORTED; - - /* - * Older versions of usbfs place a 16kb limit on bulk URBs. We work - * around this by splitting large transfers into 16k blocks, and then - * submit all urbs at once. it would be simpler to submit one urb at - * a time, but there is a big performance gain doing it this way. - * - * Newer versions lift the 16k limit (USBFS_CAP_NO_PACKET_SIZE_LIM), - * using arbritary large transfers can still be a bad idea though, as - * the kernel needs to allocate physical contiguous memory for this, - * which may fail for large buffers. - * - * The kernel solves this problem by splitting the transfer into - * blocks itself when the host-controller is scatter-gather capable - * (USBFS_CAP_BULK_SCATTER_GATHER), which most controllers are. - * - * Last, there is the issue of short-transfers when splitting, for - * short split-transfers to work reliable USBFS_CAP_BULK_CONTINUATION - * is needed, but this is not always available. - */ - if (dpriv->caps & USBFS_CAP_BULK_SCATTER_GATHER) { - /* Good! Just submit everything in one go */ - bulk_buffer_len = transfer->length ? transfer->length : 1; - use_bulk_continuation = 0; - } else if (dpriv->caps & USBFS_CAP_BULK_CONTINUATION) { - /* Split the transfers and use bulk-continuation to - avoid issues with short-transfers */ - bulk_buffer_len = MAX_BULK_BUFFER_LENGTH; - use_bulk_continuation = 1; - } else if (dpriv->caps & USBFS_CAP_NO_PACKET_SIZE_LIM) { - /* Don't split, assume the kernel can alloc the buffer - (otherwise the submit will fail with -ENOMEM) */ - bulk_buffer_len = transfer->length ? transfer->length : 1; - use_bulk_continuation = 0; - } else { - /* Bad, splitting without bulk-continuation, short transfers - which end before the last urb will not work reliable! */ - /* Note we don't warn here as this is "normal" on kernels < - 2.6.32 and not a problem for most applications */ - bulk_buffer_len = MAX_BULK_BUFFER_LENGTH; - use_bulk_continuation = 0; - } - - int num_urbs = transfer->length / bulk_buffer_len; - int last_urb_partial = 0; - - if (transfer->length == 0) { - num_urbs = 1; - } else if ((transfer->length % bulk_buffer_len) > 0) { - last_urb_partial = 1; - num_urbs++; - } - usbi_dbg("need %d urbs for new transfer with length %d", num_urbs, - transfer->length); - alloc_size = num_urbs * sizeof(struct usbfs_urb); - urbs = calloc(1, alloc_size); - if (!urbs) - return LIBUSB_ERROR_NO_MEM; - tpriv->urbs = urbs; - tpriv->num_urbs = num_urbs; - tpriv->num_retired = 0; - tpriv->reap_action = NORMAL; - tpriv->reap_status = LIBUSB_TRANSFER_COMPLETED; - - for (i = 0; i < num_urbs; i++) { - struct usbfs_urb *urb = &urbs[i]; - urb->usercontext = itransfer; - urb->type = urb_type; - urb->endpoint = transfer->endpoint; - urb->buffer = transfer->buffer + (i * bulk_buffer_len); - /* don't set the short not ok flag for the last URB */ - if (use_bulk_continuation && !is_out && (i < num_urbs - 1)) - urb->flags = USBFS_URB_SHORT_NOT_OK; - if (i == num_urbs - 1 && last_urb_partial) - urb->buffer_length = transfer->length % bulk_buffer_len; - else if (transfer->length == 0) - urb->buffer_length = 0; - else - urb->buffer_length = bulk_buffer_len; - - if (i > 0 && use_bulk_continuation) - urb->flags |= USBFS_URB_BULK_CONTINUATION; - - /* we have already checked that the flag is supported */ - if (is_out && i == num_urbs - 1 && - transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) - urb->flags |= USBFS_URB_ZERO_PACKET; - - r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb); - if (r < 0) { - if (errno == ENODEV) { - r = LIBUSB_ERROR_NO_DEVICE; - } else { - usbi_err(TRANSFER_CTX(transfer), - "submiturb failed error %d errno=%d", r, errno); - r = LIBUSB_ERROR_IO; - } - - /* if the first URB submission fails, we can simply free up and - * return failure immediately. */ - if (i == 0) { - usbi_dbg("first URB failed, easy peasy"); - free(urbs); - tpriv->urbs = NULL; - return r; - } - - /* if it's not the first URB that failed, the situation is a bit - * tricky. we may need to discard all previous URBs. there are - * complications: - * - discarding is asynchronous - discarded urbs will be reaped - * later. the user must not have freed the transfer when the - * discarded URBs are reaped, otherwise libusbx will be using - * freed memory. - * - the earlier URBs may have completed successfully and we do - * not want to throw away any data. - * - this URB failing may be no error; EREMOTEIO means that - * this transfer simply didn't need all the URBs we submitted - * so, we report that the transfer was submitted successfully and - * in case of error we discard all previous URBs. later when - * the final reap completes we can report error to the user, - * or success if an earlier URB was completed successfully. - */ - tpriv->reap_action = EREMOTEIO == errno ? COMPLETED_EARLY : SUBMIT_FAILED; - - /* The URBs we haven't submitted yet we count as already - * retired. */ - tpriv->num_retired += num_urbs - i; - - /* If we completed short then don't try to discard. */ - if (COMPLETED_EARLY == tpriv->reap_action) - return 0; - - discard_urbs(itransfer, 0, i); - - usbi_dbg("reporting successful submission but waiting for %d " - "discards before reporting error", i); - return 0; - } - } - - return 0; -} - -static int submit_iso_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct linux_device_handle_priv *dpriv = - _device_handle_priv(transfer->dev_handle); - struct usbfs_urb **urbs; - size_t alloc_size; - int num_packets = transfer->num_iso_packets; - int i; - int this_urb_len = 0; - int num_urbs = 1; - int packet_offset = 0; - unsigned int packet_len; - unsigned char *urb_buffer = transfer->buffer; - - if (tpriv->iso_urbs) - return LIBUSB_ERROR_BUSY; - - /* usbfs places a 32kb limit on iso URBs. we divide up larger requests - * into smaller units to meet such restriction, then fire off all the - * units at once. it would be simpler if we just fired one unit at a time, - * but there is a big performance gain through doing it this way. - * - * Newer kernels lift the 32k limit (USBFS_CAP_NO_PACKET_SIZE_LIM), - * using arbritary large transfers is still be a bad idea though, as - * the kernel needs to allocate physical contiguous memory for this, - * which may fail for large buffers. - */ - - /* calculate how many URBs we need */ - for (i = 0; i < num_packets; i++) { - unsigned int space_remaining = MAX_ISO_BUFFER_LENGTH - this_urb_len; - packet_len = transfer->iso_packet_desc[i].length; - - if (packet_len > space_remaining) { - num_urbs++; - this_urb_len = packet_len; - } else { - this_urb_len += packet_len; - } - } - usbi_dbg("need %d 32k URBs for transfer", num_urbs); - - alloc_size = num_urbs * sizeof(*urbs); - urbs = calloc(1, alloc_size); - if (!urbs) - return LIBUSB_ERROR_NO_MEM; - - tpriv->iso_urbs = urbs; - tpriv->num_urbs = num_urbs; - tpriv->num_retired = 0; - tpriv->reap_action = NORMAL; - tpriv->iso_packet_offset = 0; - - /* allocate + initialize each URB with the correct number of packets */ - for (i = 0; i < num_urbs; i++) { - struct usbfs_urb *urb; - unsigned int space_remaining_in_urb = MAX_ISO_BUFFER_LENGTH; - int urb_packet_offset = 0; - unsigned char *urb_buffer_orig = urb_buffer; - int j; - int k; - - /* swallow up all the packets we can fit into this URB */ - while (packet_offset < transfer->num_iso_packets) { - packet_len = transfer->iso_packet_desc[packet_offset].length; - if (packet_len <= space_remaining_in_urb) { - /* throw it in */ - urb_packet_offset++; - packet_offset++; - space_remaining_in_urb -= packet_len; - urb_buffer += packet_len; - } else { - /* it can't fit, save it for the next URB */ - break; - } - } - - alloc_size = sizeof(*urb) - + (urb_packet_offset * sizeof(struct usbfs_iso_packet_desc)); - urb = calloc(1, alloc_size); - if (!urb) { - free_iso_urbs(tpriv); - return LIBUSB_ERROR_NO_MEM; - } - urbs[i] = urb; - - /* populate packet lengths */ - for (j = 0, k = packet_offset - urb_packet_offset; - k < packet_offset; k++, j++) { - packet_len = transfer->iso_packet_desc[k].length; - urb->iso_frame_desc[j].length = packet_len; - } - - urb->usercontext = itransfer; - urb->type = USBFS_URB_TYPE_ISO; - /* FIXME: interface for non-ASAP data? */ - urb->flags = USBFS_URB_ISO_ASAP; - urb->endpoint = transfer->endpoint; - urb->number_of_packets = urb_packet_offset; - urb->buffer = urb_buffer_orig; - } - - /* submit URBs */ - for (i = 0; i < num_urbs; i++) { - int r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urbs[i]); - if (r < 0) { - if (errno == ENODEV) { - r = LIBUSB_ERROR_NO_DEVICE; - } else { - usbi_err(TRANSFER_CTX(transfer), - "submiturb failed error %d errno=%d", r, errno); - r = LIBUSB_ERROR_IO; - } - - /* if the first URB submission fails, we can simply free up and - * return failure immediately. */ - if (i == 0) { - usbi_dbg("first URB failed, easy peasy"); - free_iso_urbs(tpriv); - return r; - } - - /* if it's not the first URB that failed, the situation is a bit - * tricky. we must discard all previous URBs. there are - * complications: - * - discarding is asynchronous - discarded urbs will be reaped - * later. the user must not have freed the transfer when the - * discarded URBs are reaped, otherwise libusbx will be using - * freed memory. - * - the earlier URBs may have completed successfully and we do - * not want to throw away any data. - * so, in this case we discard all the previous URBs BUT we report - * that the transfer was submitted successfully. then later when - * the final discard completes we can report error to the user. - */ - tpriv->reap_action = SUBMIT_FAILED; - - /* The URBs we haven't submitted yet we count as already - * retired. */ - tpriv->num_retired = num_urbs - i; - discard_urbs(itransfer, 0, i); - - usbi_dbg("reporting successful submission but waiting for %d " - "discards before reporting error", i); - return 0; - } - } - - return 0; -} - -static int submit_control_transfer(struct usbi_transfer *itransfer) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_device_handle_priv *dpriv = - _device_handle_priv(transfer->dev_handle); - struct usbfs_urb *urb; - int r; - - if (tpriv->urbs) - return LIBUSB_ERROR_BUSY; - - if (transfer->length - LIBUSB_CONTROL_SETUP_SIZE > MAX_CTRL_BUFFER_LENGTH) - return LIBUSB_ERROR_INVALID_PARAM; - - urb = calloc(1, sizeof(struct usbfs_urb)); - if (!urb) - return LIBUSB_ERROR_NO_MEM; - tpriv->urbs = urb; - tpriv->num_urbs = 1; - tpriv->reap_action = NORMAL; - - urb->usercontext = itransfer; - urb->type = USBFS_URB_TYPE_CONTROL; - urb->endpoint = transfer->endpoint; - urb->buffer = transfer->buffer; - urb->buffer_length = transfer->length; - - r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb); - if (r < 0) { - free(urb); - tpriv->urbs = NULL; - if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(TRANSFER_CTX(transfer), - "submiturb failed error %d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } - return 0; -} - -static int op_submit_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return submit_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_BULK); - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_INTERRUPT); - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return submit_iso_transfer(itransfer); - default: - usbi_err(TRANSFER_CTX(transfer), - "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static int op_cancel_transfer(struct usbi_transfer *itransfer) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_BULK: - if (tpriv->reap_action == ERROR) - break; - /* else, fall through */ - case LIBUSB_TRANSFER_TYPE_CONTROL: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - tpriv->reap_action = CANCELLED; - break; - default: - usbi_err(TRANSFER_CTX(transfer), - "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } - - if (!tpriv->urbs) - return LIBUSB_ERROR_NOT_FOUND; - - return discard_urbs(itransfer, 0, tpriv->num_urbs); -} - -static void op_clear_transfer_priv(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - - /* urbs can be freed also in submit_transfer so lock mutex first */ - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - usbi_mutex_lock(&itransfer->lock); - if (tpriv->urbs) - free(tpriv->urbs); - tpriv->urbs = NULL; - usbi_mutex_unlock(&itransfer->lock); - break; - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - usbi_mutex_lock(&itransfer->lock); - if (tpriv->iso_urbs) - free_iso_urbs(tpriv); - usbi_mutex_unlock(&itransfer->lock); - break; - default: - usbi_err(TRANSFER_CTX(transfer), - "unknown endpoint type %d", transfer->type); - } -} - -static int handle_bulk_completion(struct usbi_transfer *itransfer, - struct usbfs_urb *urb) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - int urb_idx = urb - tpriv->urbs; - - usbi_mutex_lock(&itransfer->lock); - usbi_dbg("handling completion status %d of bulk urb %d/%d", urb->status, - urb_idx + 1, tpriv->num_urbs); - - tpriv->num_retired++; - - if (tpriv->reap_action != NORMAL) { - /* cancelled, submit_fail, or completed early */ - usbi_dbg("abnormal reap: urb status %d", urb->status); - - /* even though we're in the process of cancelling, it's possible that - * we may receive some data in these URBs that we don't want to lose. - * examples: - * 1. while the kernel is cancelling all the packets that make up an - * URB, a few of them might complete. so we get back a successful - * cancellation *and* some data. - * 2. we receive a short URB which marks the early completion condition, - * so we start cancelling the remaining URBs. however, we're too - * slow and another URB completes (or at least completes partially). - * (this can't happen since we always use BULK_CONTINUATION.) - * - * When this happens, our objectives are not to lose any "surplus" data, - * and also to stick it at the end of the previously-received data - * (closing any holes), so that libusbx reports the total amount of - * transferred data and presents it in a contiguous chunk. - */ - if (urb->actual_length > 0) { - unsigned char *target = transfer->buffer + itransfer->transferred; - usbi_dbg("received %d bytes of surplus data", urb->actual_length); - if (urb->buffer != target) { - usbi_dbg("moving surplus data from offset %d to offset %d", - (unsigned char *) urb->buffer - transfer->buffer, - target - transfer->buffer); - memmove(target, urb->buffer, urb->actual_length); - } - itransfer->transferred += urb->actual_length; - } - - if (tpriv->num_retired == tpriv->num_urbs) { - usbi_dbg("abnormal reap: last URB handled, reporting"); - if (tpriv->reap_action != COMPLETED_EARLY && - tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED) - tpriv->reap_status = LIBUSB_TRANSFER_ERROR; - goto completed; - } - goto out_unlock; - } - - itransfer->transferred += urb->actual_length; - - /* Many of these errors can occur on *any* urb of a multi-urb - * transfer. When they do, we tear down the rest of the transfer. - */ - switch (urb->status) { - case 0: - break; - case -EREMOTEIO: /* short transfer */ - break; - case -ENOENT: /* cancelled */ - case -ECONNRESET: - break; - case -ENODEV: - case -ESHUTDOWN: - usbi_dbg("device removed"); - tpriv->reap_status = LIBUSB_TRANSFER_NO_DEVICE; - goto cancel_remaining; - case -EPIPE: - usbi_dbg("detected endpoint stall"); - if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED) - tpriv->reap_status = LIBUSB_TRANSFER_STALL; - goto cancel_remaining; - case -EOVERFLOW: - /* overflow can only ever occur in the last urb */ - usbi_dbg("overflow, actual_length=%d", urb->actual_length); - if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED) - tpriv->reap_status = LIBUSB_TRANSFER_OVERFLOW; - goto completed; - case -ETIME: - case -EPROTO: - case -EILSEQ: - case -ECOMM: - case -ENOSR: - usbi_dbg("low level error %d", urb->status); - tpriv->reap_action = ERROR; - goto cancel_remaining; - default: - usbi_warn(ITRANSFER_CTX(itransfer), - "unrecognised urb status %d", urb->status); - tpriv->reap_action = ERROR; - goto cancel_remaining; - } - - /* if we're the last urb or we got less data than requested then we're - * done */ - if (urb_idx == tpriv->num_urbs - 1) { - usbi_dbg("last URB in transfer --> complete!"); - goto completed; - } else if (urb->actual_length < urb->buffer_length) { - usbi_dbg("short transfer %d/%d --> complete!", - urb->actual_length, urb->buffer_length); - if (tpriv->reap_action == NORMAL) - tpriv->reap_action = COMPLETED_EARLY; - } else - goto out_unlock; - -cancel_remaining: - if (ERROR == tpriv->reap_action && LIBUSB_TRANSFER_COMPLETED == tpriv->reap_status) - tpriv->reap_status = LIBUSB_TRANSFER_ERROR; - - if (tpriv->num_retired == tpriv->num_urbs) /* nothing to cancel */ - goto completed; - - /* cancel remaining urbs and wait for their completion before - * reporting results */ - discard_urbs(itransfer, urb_idx + 1, tpriv->num_urbs); - -out_unlock: - usbi_mutex_unlock(&itransfer->lock); - return 0; - -completed: - free(tpriv->urbs); - tpriv->urbs = NULL; - usbi_mutex_unlock(&itransfer->lock); - return CANCELLED == tpriv->reap_action ? - usbi_handle_transfer_cancellation(itransfer) : - usbi_handle_transfer_completion(itransfer, tpriv->reap_status); -} - -static int handle_iso_completion(struct usbi_transfer *itransfer, - struct usbfs_urb *urb) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - int num_urbs = tpriv->num_urbs; - int urb_idx = 0; - int i; - enum libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED; - - usbi_mutex_lock(&itransfer->lock); - for (i = 0; i < num_urbs; i++) { - if (urb == tpriv->iso_urbs[i]) { - urb_idx = i + 1; - break; - } - } - if (urb_idx == 0) { - usbi_err(TRANSFER_CTX(transfer), "could not locate urb!"); - usbi_mutex_unlock(&itransfer->lock); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("handling completion status %d of iso urb %d/%d", urb->status, - urb_idx, num_urbs); - - /* copy isochronous results back in */ - - for (i = 0; i < urb->number_of_packets; i++) { - struct usbfs_iso_packet_desc *urb_desc = &urb->iso_frame_desc[i]; - struct libusb_iso_packet_descriptor *lib_desc = - &transfer->iso_packet_desc[tpriv->iso_packet_offset++]; - lib_desc->status = LIBUSB_TRANSFER_COMPLETED; - switch (urb_desc->status) { - case 0: - break; - case -ENOENT: /* cancelled */ - case -ECONNRESET: - break; - case -ENODEV: - case -ESHUTDOWN: - usbi_dbg("device removed"); - lib_desc->status = LIBUSB_TRANSFER_NO_DEVICE; - break; - case -EPIPE: - usbi_dbg("detected endpoint stall"); - lib_desc->status = LIBUSB_TRANSFER_STALL; - break; - case -EOVERFLOW: - usbi_dbg("overflow error"); - lib_desc->status = LIBUSB_TRANSFER_OVERFLOW; - break; - case -ETIME: - case -EPROTO: - case -EILSEQ: - case -ECOMM: - case -ENOSR: - case -EXDEV: - usbi_dbg("low-level USB error %d", urb_desc->status); - lib_desc->status = LIBUSB_TRANSFER_ERROR; - break; - default: - usbi_warn(TRANSFER_CTX(transfer), - "unrecognised urb status %d", urb_desc->status); - lib_desc->status = LIBUSB_TRANSFER_ERROR; - break; - } - lib_desc->actual_length = urb_desc->actual_length; - } - - tpriv->num_retired++; - - if (tpriv->reap_action != NORMAL) { /* cancelled or submit_fail */ - usbi_dbg("CANCEL: urb status %d", urb->status); - - if (tpriv->num_retired == num_urbs) { - usbi_dbg("CANCEL: last URB handled, reporting"); - free_iso_urbs(tpriv); - if (tpriv->reap_action == CANCELLED) { - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_cancellation(itransfer); - } else { - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_completion(itransfer, - LIBUSB_TRANSFER_ERROR); - } - } - goto out; - } - - switch (urb->status) { - case 0: - break; - case -ENOENT: /* cancelled */ - case -ECONNRESET: - break; - case -ESHUTDOWN: - usbi_dbg("device removed"); - status = LIBUSB_TRANSFER_NO_DEVICE; - break; - default: - usbi_warn(TRANSFER_CTX(transfer), - "unrecognised urb status %d", urb->status); - status = LIBUSB_TRANSFER_ERROR; - break; - } - - /* if we're the last urb then we're done */ - if (urb_idx == num_urbs) { - usbi_dbg("last URB in transfer --> complete!"); - free_iso_urbs(tpriv); - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_completion(itransfer, status); - } - -out: - usbi_mutex_unlock(&itransfer->lock); - return 0; -} - -static int handle_control_completion(struct usbi_transfer *itransfer, - struct usbfs_urb *urb) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - int status; - - usbi_mutex_lock(&itransfer->lock); - usbi_dbg("handling completion status %d", urb->status); - - itransfer->transferred += urb->actual_length; - - if (tpriv->reap_action == CANCELLED) { - if (urb->status != 0 && urb->status != -ENOENT) - usbi_warn(ITRANSFER_CTX(itransfer), - "cancel: unrecognised urb status %d", urb->status); - free(tpriv->urbs); - tpriv->urbs = NULL; - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_cancellation(itransfer); - } - - switch (urb->status) { - case 0: - status = LIBUSB_TRANSFER_COMPLETED; - break; - case -ENOENT: /* cancelled */ - status = LIBUSB_TRANSFER_CANCELLED; - break; - case -ENODEV: - case -ESHUTDOWN: - usbi_dbg("device removed"); - status = LIBUSB_TRANSFER_NO_DEVICE; - break; - case -EPIPE: - usbi_dbg("unsupported control request"); - status = LIBUSB_TRANSFER_STALL; - break; - case -EOVERFLOW: - usbi_dbg("control overflow error"); - status = LIBUSB_TRANSFER_OVERFLOW; - break; - case -ETIME: - case -EPROTO: - case -EILSEQ: - case -ECOMM: - case -ENOSR: - usbi_dbg("low-level bus error occurred"); - status = LIBUSB_TRANSFER_ERROR; - break; - default: - usbi_warn(ITRANSFER_CTX(itransfer), - "unrecognised urb status %d", urb->status); - status = LIBUSB_TRANSFER_ERROR; - break; - } - - free(tpriv->urbs); - tpriv->urbs = NULL; - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_completion(itransfer, status); -} - -static int reap_for_handle(struct libusb_device_handle *handle) -{ - struct linux_device_handle_priv *hpriv = _device_handle_priv(handle); - int r; - struct usbfs_urb *urb; - struct usbi_transfer *itransfer; - struct libusb_transfer *transfer; - - r = ioctl(hpriv->fd, IOCTL_USBFS_REAPURBNDELAY, &urb); - if (r == -1 && errno == EAGAIN) - return 1; - if (r < 0) { - if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), "reap failed error %d errno=%d", - r, errno); - return LIBUSB_ERROR_IO; - } - - itransfer = urb->usercontext; - transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - usbi_dbg("urb type=%d status=%d transferred=%d", urb->type, urb->status, - urb->actual_length); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return handle_iso_completion(itransfer, urb); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return handle_bulk_completion(itransfer, urb); - case LIBUSB_TRANSFER_TYPE_CONTROL: - return handle_control_completion(itransfer, urb); - default: - usbi_err(HANDLE_CTX(handle), "unrecognised endpoint type %x", - transfer->type); - return LIBUSB_ERROR_OTHER; - } -} - -static int op_handle_events(struct libusb_context *ctx, - struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready) -{ - int r; - unsigned int i = 0; - - usbi_mutex_lock(&ctx->open_devs_lock); - for (i = 0; i < nfds && num_ready > 0; i++) { - struct pollfd *pollfd = &fds[i]; - struct libusb_device_handle *handle; - struct linux_device_handle_priv *hpriv = NULL; - - if (!pollfd->revents) - continue; - - num_ready--; - list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) { - hpriv = _device_handle_priv(handle); - if (hpriv->fd == pollfd->fd) - break; - } - - if (pollfd->revents & POLLERR) { - usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd); - usbi_handle_disconnect(handle); - continue; - } - - do { - r = reap_for_handle(handle); - } while (r == 0); - if (r == 1 || r == LIBUSB_ERROR_NO_DEVICE) - continue; - else if (r < 0) - goto out; - } - - r = 0; -out: - usbi_mutex_unlock(&ctx->open_devs_lock); - return r; -} - -static int op_clock_gettime(int clk_id, struct timespec *tp) -{ - switch (clk_id) { - case USBI_CLOCK_MONOTONIC: - return clock_gettime(monotonic_clkid, tp); - case USBI_CLOCK_REALTIME: - return clock_gettime(CLOCK_REALTIME, tp); - default: - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -#ifdef USBI_TIMERFD_AVAILABLE -static clockid_t op_get_timerfd_clockid(void) -{ - return monotonic_clkid; - -} -#endif - -const struct usbi_os_backend linux_usbfs_backend = { - .name = "Linux usbfs", - .caps = USBI_CAP_HAS_HID_ACCESS|USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER, - .init = op_init, - .exit = op_exit, - .get_device_list = NULL, - .hotplug_poll = op_hotplug_poll, - .get_device_descriptor = op_get_device_descriptor, - .get_active_config_descriptor = op_get_active_config_descriptor, - .get_config_descriptor = op_get_config_descriptor, - .get_config_descriptor_by_value = op_get_config_descriptor_by_value, - - .open = op_open, - .close = op_close, - .get_configuration = op_get_configuration, - .set_configuration = op_set_configuration, - .claim_interface = op_claim_interface, - .release_interface = op_release_interface, - - .set_interface_altsetting = op_set_interface, - .clear_halt = op_clear_halt, - .reset_device = op_reset_device, - - .kernel_driver_active = op_kernel_driver_active, - .detach_kernel_driver = op_detach_kernel_driver, - .attach_kernel_driver = op_attach_kernel_driver, - - .destroy_device = op_destroy_device, - - .submit_transfer = op_submit_transfer, - .cancel_transfer = op_cancel_transfer, - .clear_transfer_priv = op_clear_transfer_priv, - - .handle_events = op_handle_events, - - .clock_gettime = op_clock_gettime, - -#ifdef USBI_TIMERFD_AVAILABLE - .get_timerfd_clockid = op_get_timerfd_clockid, -#endif - - .device_priv_size = sizeof(struct linux_device_priv), - .device_handle_priv_size = sizeof(struct linux_device_handle_priv), - .transfer_priv_size = sizeof(struct linux_transfer_priv), - .add_iso_packet_size = 0, -}; diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/linux_usbfs.h b/src/3rd_party-static/libusbx-1.0.16/libusb/os/linux_usbfs.h deleted file mode 100644 index 499bab78e8..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/linux_usbfs.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * usbfs header structures - * 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 - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LIBUSB_USBFS_H -#define LIBUSB_USBFS_H - -#include <linux/types.h> - -#define SYSFS_DEVICE_PATH "/sys/bus/usb/devices" - -struct usbfs_ctrltransfer { - /* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */ - uint8_t bmRequestType; - uint8_t bRequest; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; - - uint32_t timeout; /* in milliseconds */ - - /* pointer to data */ - void *data; -}; - -struct usbfs_bulktransfer { - /* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */ - unsigned int ep; - unsigned int len; - unsigned int timeout; /* in milliseconds */ - - /* pointer to data */ - void *data; -}; - -struct usbfs_setinterface { - /* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */ - unsigned int interface; - unsigned int altsetting; -}; - -#define USBFS_MAXDRIVERNAME 255 - -struct usbfs_getdriver { - unsigned int interface; - char driver[USBFS_MAXDRIVERNAME + 1]; -}; - -#define USBFS_URB_SHORT_NOT_OK 0x01 -#define USBFS_URB_ISO_ASAP 0x02 -#define USBFS_URB_BULK_CONTINUATION 0x04 -#define USBFS_URB_QUEUE_BULK 0x10 -#define USBFS_URB_ZERO_PACKET 0x40 - -enum usbfs_urb_type { - USBFS_URB_TYPE_ISO = 0, - USBFS_URB_TYPE_INTERRUPT = 1, - USBFS_URB_TYPE_CONTROL = 2, - USBFS_URB_TYPE_BULK = 3, -}; - -struct usbfs_iso_packet_desc { - unsigned int length; - unsigned int actual_length; - unsigned int status; -}; - -#define MAX_ISO_BUFFER_LENGTH 32768 -#define MAX_BULK_BUFFER_LENGTH 16384 -#define MAX_CTRL_BUFFER_LENGTH 4096 - -struct usbfs_urb { - unsigned char type; - unsigned char endpoint; - int status; - unsigned int flags; - void *buffer; - int buffer_length; - int actual_length; - int start_frame; - int number_of_packets; - int error_count; - unsigned int signr; - void *usercontext; - struct usbfs_iso_packet_desc iso_frame_desc[0]; -}; - -struct usbfs_connectinfo { - unsigned int devnum; - unsigned char slow; -}; - -struct usbfs_ioctl { - int ifno; /* interface 0..N ; negative numbers reserved */ - int ioctl_code; /* MUST encode size + direction of data so the - * macros in <asm/ioctl.h> give correct values */ - void *data; /* param buffer (in, or out) */ -}; - -struct usbfs_hub_portinfo { - unsigned char numports; - unsigned char port[127]; /* port to device num mapping */ -}; - -#define USBFS_CAP_ZERO_PACKET 0x01 -#define USBFS_CAP_BULK_CONTINUATION 0x02 -#define USBFS_CAP_NO_PACKET_SIZE_LIM 0x04 -#define USBFS_CAP_BULK_SCATTER_GATHER 0x08 - -#define 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_BULK _IOWR('U', 2, struct usbfs_bulktransfer) -#define IOCTL_USBFS_RESETEP _IOR('U', 3, unsigned int) -#define IOCTL_USBFS_SETINTF _IOR('U', 4, struct usbfs_setinterface) -#define IOCTL_USBFS_SETCONFIG _IOR('U', 5, unsigned int) -#define IOCTL_USBFS_GETDRIVER _IOW('U', 8, struct usbfs_getdriver) -#define IOCTL_USBFS_SUBMITURB _IOR('U', 10, struct usbfs_urb) -#define IOCTL_USBFS_DISCARDURB _IO('U', 11) -#define IOCTL_USBFS_REAPURB _IOW('U', 12, void *) -#define IOCTL_USBFS_REAPURBNDELAY _IOW('U', 13, void *) -#define IOCTL_USBFS_CLAIMINTF _IOR('U', 15, unsigned int) -#define IOCTL_USBFS_RELEASEINTF _IOR('U', 16, unsigned int) -#define IOCTL_USBFS_CONNECTINFO _IOW('U', 17, struct usbfs_connectinfo) -#define IOCTL_USBFS_IOCTL _IOWR('U', 18, struct usbfs_ioctl) -#define IOCTL_USBFS_HUB_PORTINFO _IOR('U', 19, struct usbfs_hub_portinfo) -#define IOCTL_USBFS_RESET _IO('U', 20) -#define IOCTL_USBFS_CLEAR_HALT _IOR('U', 21, unsigned int) -#define IOCTL_USBFS_DISCONNECT _IO('U', 22) -#define IOCTL_USBFS_CONNECT _IO('U', 23) -#define IOCTL_USBFS_CLAIM_PORT _IOR('U', 24, unsigned int) -#define IOCTL_USBFS_RELEASE_PORT _IOR('U', 25, unsigned int) -#define IOCTL_USBFS_GET_CAPABILITIES _IOR('U', 26, __u32) -#define IOCTL_USBFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbfs_disconnect_claim) - -extern usbi_mutex_static_t linux_hotplug_lock; - -#if defined(HAVE_LIBUDEV) -int linux_udev_start_event_monitor(void); -int linux_udev_stop_event_monitor(void); -int linux_udev_scan_devices(struct libusb_context *ctx); -void linux_udev_hotplug_poll(void); -#else -int linux_netlink_start_event_monitor(void); -int linux_netlink_stop_event_monitor(void); -void linux_netlink_hotplug_poll(void); -#endif - -void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name); -void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name); - -int linux_get_device_address (struct libusb_context *ctx, int detached, - uint8_t *busnum, uint8_t *devaddr, const char *dev_node, - const char *sys_name); -int linux_enumerate_device(struct libusb_context *ctx, - uint8_t busnum, uint8_t devaddr, const char *sysfs_dir); - -#endif diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/openbsd_usb.c b/src/3rd_party-static/libusbx-1.0.16/libusb/os/openbsd_usb.c deleted file mode 100644 index f4fd4543a6..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/openbsd_usb.c +++ /dev/null @@ -1,734 +0,0 @@ -/* - * 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 obsd_get_device_list(struct libusb_context *, - struct discovered_devs **); -static int obsd_open(struct libusb_device_handle *); -static void obsd_close(struct libusb_device_handle *); - -static int obsd_get_device_descriptor(struct libusb_device *, unsigned char *, - int *); -static int obsd_get_active_config_descriptor(struct libusb_device *, - unsigned char *, size_t, int *); -static int obsd_get_config_descriptor(struct libusb_device *, uint8_t, - unsigned char *, size_t, int *); - -static int obsd_get_configuration(struct libusb_device_handle *, int *); -static int obsd_set_configuration(struct libusb_device_handle *, int); - -static int obsd_claim_interface(struct libusb_device_handle *, int); -static int obsd_release_interface(struct libusb_device_handle *, int); - -static int obsd_set_interface_altsetting(struct libusb_device_handle *, int, - int); -static int obsd_clear_halt(struct libusb_device_handle *, unsigned char); -static int obsd_reset_device(struct libusb_device_handle *); -static void obsd_destroy_device(struct libusb_device *); - -static int obsd_submit_transfer(struct usbi_transfer *); -static int obsd_cancel_transfer(struct usbi_transfer *); -static void obsd_clear_transfer_priv(struct usbi_transfer *); -static int obsd_handle_events(struct libusb_context *ctx, struct pollfd *, - nfds_t, int); -static int obsd_clock_gettime(int, struct timespec *); - -/* - * Private functions - */ -static int _errno_to_libusb(int); -static int _cache_active_config_descriptor(struct libusb_device *, int); -static int _sync_control_transfer(struct usbi_transfer *); -static int _sync_gen_transfer(struct usbi_transfer *); -static int _access_endpoint(struct libusb_transfer *); - -const struct usbi_os_backend openbsd_backend = { - "Synchronous OpenBSD backend", - 0, - NULL, /* init() */ - NULL, /* exit() */ - obsd_get_device_list, - NULL, /* hotplug_poll */ - obsd_open, - obsd_close, - - obsd_get_device_descriptor, - obsd_get_active_config_descriptor, - obsd_get_config_descriptor, - NULL, /* get_config_descriptor_by_value() */ - - obsd_get_configuration, - obsd_set_configuration, - - obsd_claim_interface, - obsd_release_interface, - - obsd_set_interface_altsetting, - obsd_clear_halt, - obsd_reset_device, - - NULL, /* kernel_driver_active() */ - NULL, /* detach_kernel_driver() */ - NULL, /* attach_kernel_driver() */ - - obsd_destroy_device, - - obsd_submit_transfer, - obsd_cancel_transfer, - obsd_clear_transfer_priv, - - obsd_handle_events, - - obsd_clock_gettime, - sizeof(struct device_priv), - sizeof(struct handle_priv), - 0, /* transfer_priv_size */ - 0, /* add_iso_packet_size */ -}; - -int -obsd_get_device_list(struct libusb_context * ctx, - struct discovered_devs **discdevs) -{ - struct libusb_device *dev; - struct device_priv *dpriv; - struct usb_device_info di; - unsigned long session_id; - char devnode[16]; - int fd, err, i; - - usbi_dbg(""); - - /* Only ugen(4) is supported */ - for (i = 0; i < USB_MAX_DEVICES; i++) { - /* Control endpoint is always .00 */ - snprintf(devnode, sizeof(devnode), "/dev/ugen%d.00", i); - - if ((fd = open(devnode, O_RDONLY)) < 0) { - if (errno != ENOENT && errno != ENXIO) - usbi_err(ctx, "could not open %s", devnode); - continue; - } - - if (ioctl(fd, USB_GET_DEVICEINFO, &di) < 0) - continue; - - session_id = (di.udi_bus << 8 | di.udi_addr); - dev = usbi_get_device_by_session_id(ctx, session_id); - - if (dev) { - 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 -obsd_open(struct libusb_device_handle *handle) -{ - struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; - struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; - - dpriv->fd = open(dpriv->devnode, O_RDWR); - if (dpriv->fd < 0) { - dpriv->fd = open(dpriv->devnode, O_RDONLY); - if (dpriv->fd < 0) - return _errno_to_libusb(errno); - } - - usbi_dbg("open %s: fd %d", dpriv->devnode, dpriv->fd); - - if (pipe(hpriv->pipe) < 0) - return _errno_to_libusb(errno); - - return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->pipe[0], POLLIN); -} - -void -obsd_close(struct libusb_device_handle *handle) -{ - struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; - struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; - - usbi_dbg("close: fd %d", dpriv->fd); - - close(dpriv->fd); - dpriv->fd = -1; - - usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]); - - close(hpriv->pipe[0]); - close(hpriv->pipe[1]); -} - -int -obsd_get_device_descriptor(struct libusb_device *dev, unsigned char *buf, - int *host_endian) -{ - struct device_priv *dpriv = (struct device_priv *)dev->os_priv; - - usbi_dbg(""); - - memcpy(buf, &dpriv->ddesc, DEVICE_DESC_LENGTH); - - *host_endian = 0; - - return (LIBUSB_SUCCESS); -} - -int -obsd_get_active_config_descriptor(struct libusb_device *dev, - unsigned char *buf, size_t len, int *host_endian) -{ - struct device_priv *dpriv = (struct device_priv *)dev->os_priv; - usb_config_descriptor_t *ucd; - - ucd = (usb_config_descriptor_t *) dpriv->cdesc; - len = MIN(len, UGETW(ucd->wTotalLength)); - - usbi_dbg("len %d", len); - - memcpy(buf, dpriv->cdesc, len); - - *host_endian = 0; - - return len; -} - -int -obsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx, - unsigned char *buf, size_t len, int *host_endian) -{ - struct device_priv *dpriv = (struct device_priv *)dev->os_priv; - struct usb_full_desc ufd; - int fd, err; - - usbi_dbg("index %d, len %d", idx, len); - - /* A config descriptor may be requested before opening the device */ - if (dpriv->fd >= 0) { - fd = dpriv->fd; - } else { - fd = open(dpriv->devnode, O_RDONLY); - if (fd < 0) - return _errno_to_libusb(errno); - } - - ufd.ufd_config_index = idx; - ufd.ufd_size = len; - ufd.ufd_data = buf; - - if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) { - err = errno; - if (dpriv->fd < 0) - close(fd); - return _errno_to_libusb(err); - } - - if (dpriv->fd < 0) - close(fd); - - *host_endian = 0; - - return len; -} - -int -obsd_get_configuration(struct libusb_device_handle *handle, int *config) -{ - struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; - - usbi_dbg(""); - - if (ioctl(dpriv->fd, USB_GET_CONFIG, config) < 0) - return _errno_to_libusb(errno); - - usbi_dbg("configuration %d", *config); - - return (LIBUSB_SUCCESS); -} - -int -obsd_set_configuration(struct libusb_device_handle *handle, int config) -{ - struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; - - usbi_dbg("configuration %d", config); - - if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0) - return _errno_to_libusb(errno); - - return _cache_active_config_descriptor(handle->dev, dpriv->fd); -} - -int -obsd_claim_interface(struct libusb_device_handle *handle, int iface) -{ - struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; - int i; - - for (i = 0; i < USB_MAX_ENDPOINTS; i++) - hpriv->endpoints[i] = -1; - - return (LIBUSB_SUCCESS); -} - -int -obsd_release_interface(struct libusb_device_handle *handle, int iface) -{ - struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; - int i; - - for (i = 0; i < USB_MAX_ENDPOINTS; i++) - if (hpriv->endpoints[i] >= 0) - close(hpriv->endpoints[i]); - - return (LIBUSB_SUCCESS); -} - -int -obsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface, - int altsetting) -{ - struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; - struct usb_alt_interface intf; - - usbi_dbg("iface %d, setting %d", iface, altsetting); - - memset(&intf, 0, sizeof(intf)); - - intf.uai_interface_index = iface; - intf.uai_alt_no = altsetting; - - if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0) - return _errno_to_libusb(errno); - - return (LIBUSB_SUCCESS); -} - -int -obsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint) -{ - struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; - struct usb_ctl_request req; - - usbi_dbg(""); - - req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT; - req.ucr_request.bRequest = UR_CLEAR_FEATURE; - USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT); - USETW(req.ucr_request.wIndex, endpoint); - USETW(req.ucr_request.wLength, 0); - - if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0) - return _errno_to_libusb(errno); - - return (LIBUSB_SUCCESS); -} - -int -obsd_reset_device(struct libusb_device_handle *handle) -{ - usbi_dbg(""); - - return (LIBUSB_ERROR_NOT_SUPPORTED); -} - -void -obsd_destroy_device(struct libusb_device *dev) -{ - struct device_priv *dpriv = (struct device_priv *)dev->os_priv; - - usbi_dbg(""); - - free(dpriv->cdesc); -} - -int -obsd_submit_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer; - struct handle_priv *hpriv; - int err = 0; - - usbi_dbg(""); - - transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - hpriv = (struct handle_priv *)transfer->dev_handle->os_priv; - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - err = _sync_control_transfer(itransfer); - break; - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - if (IS_XFEROUT(transfer)) { - /* Isochronous write is not supported */ - err = LIBUSB_ERROR_NOT_SUPPORTED; - break; - } - err = _sync_gen_transfer(itransfer); - break; - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - if (IS_XFEROUT(transfer) && - transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) { - err = LIBUSB_ERROR_NOT_SUPPORTED; - break; - } - err = _sync_gen_transfer(itransfer); - break; - } - - if (err) - return (err); - - if (write(hpriv->pipe[1], &itransfer, sizeof(itransfer)) < 0) - return _errno_to_libusb(errno); - - return (LIBUSB_SUCCESS); -} - -int -obsd_cancel_transfer(struct usbi_transfer *itransfer) -{ - usbi_dbg(""); - - return (LIBUSB_ERROR_NOT_SUPPORTED); -} - -void -obsd_clear_transfer_priv(struct usbi_transfer *itransfer) -{ - usbi_dbg(""); - - /* Nothing to do */ -} - -int -obsd_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds_t nfds, - int num_ready) -{ - struct libusb_device_handle *handle; - struct handle_priv *hpriv = NULL; - struct usbi_transfer *itransfer; - struct pollfd *pollfd; - int i, err = 0; - - usbi_dbg(""); - - pthread_mutex_lock(&ctx->open_devs_lock); - for (i = 0; i < nfds && num_ready > 0; i++) { - pollfd = &fds[i]; - - if (!pollfd->revents) - continue; - - hpriv = NULL; - num_ready--; - list_for_each_entry(handle, &ctx->open_devs, list, - struct libusb_device_handle) { - hpriv = (struct handle_priv *)handle->os_priv; - - if (hpriv->pipe[0] == pollfd->fd) - break; - - hpriv = NULL; - } - - if (NULL == hpriv) { - usbi_dbg("fd %d is not an event pipe!", pollfd->fd); - err = ENOENT; - break; - } - - if (pollfd->revents & POLLERR) { - usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]); - usbi_handle_disconnect(handle); - continue; - } - - if (read(hpriv->pipe[0], &itransfer, sizeof(itransfer)) < 0) { - err = errno; - break; - } - - if ((err = usbi_handle_transfer_completion(itransfer, - LIBUSB_TRANSFER_COMPLETED))) - break; - } - pthread_mutex_unlock(&ctx->open_devs_lock); - - if (err) - return _errno_to_libusb(err); - - return (LIBUSB_SUCCESS); -} - -int -obsd_clock_gettime(int clkid, struct timespec *tp) -{ - usbi_dbg("clock %d", clkid); - - if (clkid == USBI_CLOCK_REALTIME) - return clock_gettime(CLOCK_REALTIME, tp); - - if (clkid == USBI_CLOCK_MONOTONIC) - return clock_gettime(CLOCK_MONOTONIC, tp); - - return (LIBUSB_ERROR_INVALID_PARAM); -} - -int -_errno_to_libusb(int err) -{ - switch (err) { - case EIO: - return (LIBUSB_ERROR_IO); - case EACCES: - return (LIBUSB_ERROR_ACCESS); - case ENOENT: - return (LIBUSB_ERROR_NO_DEVICE); - case ENOMEM: - return (LIBUSB_ERROR_NO_MEM); - } - - usbi_dbg("error: %s", strerror(err)); - - return (LIBUSB_ERROR_OTHER); -} - -int -_cache_active_config_descriptor(struct libusb_device *dev, int fd) -{ - struct device_priv *dpriv = (struct device_priv *)dev->os_priv; - struct usb_config_desc ucd; - struct usb_full_desc ufd; - unsigned char* buf; - int len; - - usbi_dbg("fd %d", fd); - - ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX; - - if ((ioctl(fd, USB_GET_CONFIG_DESC, &ucd)) < 0) - return _errno_to_libusb(errno); - - usbi_dbg("active bLength %d", ucd.ucd_desc.bLength); - - len = UGETW(ucd.ucd_desc.wTotalLength); - buf = malloc(len); - if (buf == NULL) - return (LIBUSB_ERROR_NO_MEM); - - ufd.ufd_config_index = ucd.ucd_config_index; - ufd.ufd_size = len; - ufd.ufd_data = buf; - - usbi_dbg("index %d, len %d", ufd.ufd_config_index, len); - - if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) { - free(buf); - return _errno_to_libusb(errno); - } - - if (dpriv->cdesc) - free(dpriv->cdesc); - dpriv->cdesc = buf; - - return (0); -} - -int -_sync_control_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer; - struct libusb_control_setup *setup; - struct device_priv *dpriv; - struct usb_ctl_request req; - - transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv; - setup = (struct libusb_control_setup *)transfer->buffer; - - usbi_dbg("type %d request %d value %d index %d length %d timeout %d", - setup->bmRequestType, setup->bRequest, - libusb_le16_to_cpu(setup->wValue), - libusb_le16_to_cpu(setup->wIndex), - libusb_le16_to_cpu(setup->wLength), transfer->timeout); - - req.ucr_request.bmRequestType = setup->bmRequestType; - req.ucr_request.bRequest = setup->bRequest; - /* Don't use USETW, 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); -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/poll_posix.c b/src/3rd_party-static/libusbx-1.0.16/libusb/os/poll_posix.c deleted file mode 100644 index eeaf5dce49..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/poll_posix.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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; -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/poll_posix.h b/src/3rd_party-static/libusbx-1.0.16/libusb/os/poll_posix.h deleted file mode 100644 index 5b4b2c905e..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/poll_posix.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef LIBUSB_POLL_POSIX_H -#define LIBUSB_POLL_POSIX_H - -#define usbi_write write -#define usbi_read read -#define usbi_close close -#define usbi_poll poll - -int usbi_pipe(int pipefd[2]); - -#endif /* LIBUSB_POLL_POSIX_H */ diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/poll_windows.c b/src/3rd_party-static/libusbx-1.0.16/libusb/os/poll_windows.c deleted file mode 100644 index 7ed19ba324..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/poll_windows.c +++ /dev/null @@ -1,726 +0,0 @@ -/* - * poll_windows: poll compatibility wrapper for Windows - * Copyright © 2012-2013 RealVNC Ltd. - * Copyright © 2009-2010 Pete Batard <pete@akeo.ie> - * With contributions from Michael Plante, Orin Eman et al. - * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -/* - * poll() and pipe() Windows compatibility layer for libusbx 1.0 - * - * The way this layer works is by using OVERLAPPED with async I/O transfers, as - * OVERLAPPED have an associated event which is flagged for I/O completion. - * - * For USB pollable async I/O, you would typically: - * - obtain a Windows HANDLE to a file or device that has been opened in - * OVERLAPPED mode - * - call usbi_create_fd with this handle to obtain a custom fd. - * Note that if you need simultaneous R/W access, you need to call create_fd - * twice, once in RW_READ and once in RW_WRITE mode to obtain 2 separate - * pollable fds - * - leave the core functions call the poll routine and flag POLLIN/POLLOUT - * - * The pipe pollable synchronous I/O works using the overlapped event associated - * with a fake pipe. The read/write functions are only meant to be used in that - * context. - */ -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> - -#include "libusbi.h" - -// Uncomment to debug the polling layer -//#define DEBUG_POLL_WINDOWS -#if defined(DEBUG_POLL_WINDOWS) -#define poll_dbg usbi_dbg -#else -// MSVC++ < 2005 cannot use a variadic argument and non MSVC -// compilers produce warnings if parenthesis are ommitted. -#if defined(_MSC_VER) && (_MSC_VER < 1400) -#define poll_dbg -#else -#define poll_dbg(...) -#endif -#endif - -#if defined(_PREFAST_) -#pragma warning(disable:28719) -#endif - -#define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0) - -// public fd data -const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, NULL, NULL, RW_NONE}; -struct winfd poll_fd[MAX_FDS]; -// internal fd data -struct { - CRITICAL_SECTION mutex; // lock for fds - // Additional variables for XP CancelIoEx partial emulation - HANDLE original_handle; - DWORD thread_id; -} _poll_fd[MAX_FDS]; - -// globals -BOOLEAN is_polling_set = FALSE; -LONG pipe_number = 0; -static volatile LONG compat_spinlock = 0; - -#if !defined(_WIN32_WCE) -// CancelIoEx, available on Vista and later only, provides the ability to cancel -// a single transfer (OVERLAPPED) when used. As it may not be part of any of the -// platform headers, we hook into the Kernel32 system DLL directly to seek it. -static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL; -#define 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)) { - 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; - } - if (pCancelIoEx != NULL) { - return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped); - } - if (_poll_fd[_index].thread_id == GetCurrentThreadId()) { - return CancelIo(poll_fd[_index].handle); - } - usbi_warn(NULL, "Unable to cancel I/O that was started from another thread"); - return FALSE; -} -#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 -void init_polling(void) -{ - int i; - - while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { - SleepEx(0, TRUE); - } - if (!is_polling_set) { - setup_cancel_io(); - for (i=0; i<MAX_FDS; i++) { - poll_fd[i] = INVALID_WINFD; - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - _poll_fd[i].thread_id = 0; - InitializeCriticalSection(&_poll_fd[i].mutex); - } - is_polling_set = TRUE; - } - InterlockedExchange((LONG *)&compat_spinlock, 0); -} - -// Internal function to retrieve the table index (and lock the fd mutex) -static int _fd_to_index_and_lock(int fd) -{ - int i; - - if (fd < 0) - return -1; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd == fd) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have changed before we got to critical - if (poll_fd[i].fd != fd) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - return i; - } - } - return -1; -} - -static OVERLAPPED *create_overlapped(void) -{ - OVERLAPPED *overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED)); - if (overlapped == NULL) { - return NULL; - } - overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if(overlapped->hEvent == NULL) { - free (overlapped); - return NULL; - } - return overlapped; -} - -static void free_overlapped(OVERLAPPED *overlapped) -{ - if (overlapped == NULL) - return; - - if ( (overlapped->hEvent != 0) - && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) { - CloseHandle(overlapped->hEvent); - } - free(overlapped); -} - -void exit_polling(void) -{ - int i; - - while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { - SleepEx(0, TRUE); - } - if (is_polling_set) { - is_polling_set = FALSE; - - for (i=0; i<MAX_FDS; i++) { - // Cancel any async I/O (handle can be invalid) - cancel_io(i); - // If anything was pending on that I/O, it should be - // terminating, and we should be able to access the fd - // mutex lock before too long - EnterCriticalSection(&_poll_fd[i].mutex); - free_overlapped(poll_fd[i].overlapped); - if (Use_Duplicate_Handles) { - // Close duplicate handle - if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) { - CloseHandle(poll_fd[i].handle); - } - } - poll_fd[i] = INVALID_WINFD; - LeaveCriticalSection(&_poll_fd[i].mutex); - DeleteCriticalSection(&_poll_fd[i].mutex); - } - } - InterlockedExchange((LONG *)&compat_spinlock, 0); -} - -/* - * Create a fake pipe. - * 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 - * to access that event. - */ -int usbi_pipe(int filedes[2]) -{ - int i; - OVERLAPPED* overlapped; - - CHECK_INIT_POLLING; - - overlapped = create_overlapped(); - - if (overlapped == NULL) { - return -1; - } - // The overlapped must have status pending for signaling to work in poll - overlapped->Internal = STATUS_PENDING; - overlapped->InternalHigh = 0; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd < 0) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been allocated before we got to critical - if (poll_fd[i].fd >= 0) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - - // 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].overlapped = overlapped; - // There's no polling on the write end, so we just use READ for our needs - poll_fd[i].rw = RW_READ; - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - LeaveCriticalSection(&_poll_fd[i].mutex); - return 0; - } - } - free_overlapped(overlapped); - return -1; -} - -/* - * Create both an fd and an OVERLAPPED from an open Windows handle, so that - * it can be used with our polling function - * The handle MUST support overlapped transfers (usually requires CreateFile - * with FILE_FLAG_OVERLAPPED) - * Return a pollable file descriptor struct, or INVALID_WINFD on error - * - * Note that the fd returned by this function is a per-transfer fd, rather - * than a per-session fd and cannot be used for anything else but our - * custom functions (the fd itself points to the NUL: device) - * if you plan to do R/W on the same handle, you MUST create 2 fds: one for - * read and one for write. Using a single R/W fd is unsupported and will - * produce unexpected results - */ -struct winfd usbi_create_fd(HANDLE handle, int access_mode, struct usbi_transfer *itransfer, cancel_transfer *cancel_fn) -{ - int i; - struct winfd wfd = INVALID_WINFD; - OVERLAPPED* overlapped = NULL; - - CHECK_INIT_POLLING; - - if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) { - return INVALID_WINFD; - } - - 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."); - return INVALID_WINFD; - } - if (access_mode == RW_READ) { - wfd.rw = RW_READ; - } else { - wfd.rw = RW_WRITE; - } - - overlapped = create_overlapped(); - if(overlapped == NULL) { - return INVALID_WINFD; - } - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd < 0) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been removed before we got to critical - if (poll_fd[i].fd >= 0) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - // Use index as the unique fd number - wfd.fd = i; - // Attempt to emulate some of the CancelIoEx behaviour on platforms - // that don't have it - if (Use_Duplicate_Handles) { - _poll_fd[i].thread_id = GetCurrentThreadId(); - if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), - &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) { - usbi_dbg("could not duplicate handle for CancelIo - using original one"); - wfd.handle = handle; - // Make sure we won't close the original handle on fd deletion then - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - } else { - _poll_fd[i].original_handle = handle; - } - } else { - wfd.handle = handle; - } - wfd.overlapped = overlapped; - memcpy(&poll_fd[i], &wfd, sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - free_overlapped(overlapped); - return INVALID_WINFD; -} - -static void _free_index(int _index) -{ - // Cancel any async IO (Don't care about the validity of our handles for this) - cancel_io(_index); - // close the duplicate handle (if we have an actual duplicate) - if (Use_Duplicate_Handles) { - if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) { - CloseHandle(poll_fd[_index].handle); - } - _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE; - _poll_fd[_index].thread_id = 0; - } - free_overlapped(poll_fd[_index].overlapped); - poll_fd[_index] = INVALID_WINFD; -} - -/* - * Release a pollable file descriptor. - * - * Note that the associated Windows handle is not closed by this call - */ -void usbi_free_fd(struct winfd *wfd) -{ - int _index; - - CHECK_INIT_POLLING; - - _index = _fd_to_index_and_lock(wfd->fd); - if (_index < 0) { - return; - } - _free_index(_index); - *wfd = INVALID_WINFD; - LeaveCriticalSection(&_poll_fd[_index].mutex); -} - -/* - * The functions below perform various conversions between fd, handle and OVERLAPPED - */ -struct winfd fd_to_winfd(int fd) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if (fd <= 0) - return INVALID_WINFD; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd == fd) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been deleted before we got to critical - if (poll_fd[i].fd != fd) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - return INVALID_WINFD; -} - -struct winfd handle_to_winfd(HANDLE handle) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) - return INVALID_WINFD; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].handle == handle) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been deleted before we got to critical - if (poll_fd[i].handle != handle) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - return INVALID_WINFD; -} - -struct winfd overlapped_to_winfd(OVERLAPPED* overlapped) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if (overlapped == NULL) - return INVALID_WINFD; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].overlapped == overlapped) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been deleted before we got to critical - if (poll_fd[i].overlapped != overlapped) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - return INVALID_WINFD; -} - -/* - * POSIX poll equivalent, using Windows OVERLAPPED - * Currently, this function only accepts one of POLLIN or POLLOUT per fd - * (but you can create multiple fds from the same handle for read and write) - */ -int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) -{ - unsigned i; - int _index, object_index, triggered; - HANDLE *handles_to_wait_on; - int *handle_to_index; - DWORD nb_handles_to_wait_on = 0; - DWORD ret; - - CHECK_INIT_POLLING; - - triggered = 0; - handles_to_wait_on = (HANDLE*) calloc(nfds+1, sizeof(HANDLE)); // +1 for fd_update - handle_to_index = (int*) calloc(nfds, sizeof(int)); - if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) { - errno = ENOMEM; - triggered = -1; - goto poll_exit; - } - - for (i = 0; i < nfds; ++i) { - fds[i].revents = 0; - - // Only one of POLLIN or POLLOUT can be selected with this version of poll (not both) - if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) { - fds[i].revents |= POLLERR; - errno = EACCES; - usbi_warn(NULL, "unsupported set of events"); - triggered = -1; - goto poll_exit; - } - - _index = _fd_to_index_and_lock(fds[i].fd); - poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[_index].fd, poll_fd[_index].overlapped, fds[i].events); - - if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) - || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - if (_index >= 0) { - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - usbi_warn(NULL, "invalid fd"); - triggered = -1; - goto poll_exit; - } - - // IN or OUT must match our fd direction - if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - usbi_warn(NULL, "attempted POLLIN on fd without READ access"); - LeaveCriticalSection(&_poll_fd[_index].mutex); - triggered = -1; - goto poll_exit; - } - - if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access"); - LeaveCriticalSection(&_poll_fd[_index].mutex); - triggered = -1; - goto poll_exit; - } - - // The following macro only works if overlapped I/O was reported pending - if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped)) - || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) { - poll_dbg(" completed"); - // checks above should ensure this works: - fds[i].revents = fds[i].events; - triggered++; - } else { - handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent; - handle_to_index[nb_handles_to_wait_on] = i; - nb_handles_to_wait_on++; - } - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - - // If nothing was triggered, wait on all fds that require it - if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) { - if (timeout < 0) { - poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on); - } else { - poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on); - } - ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on, - FALSE, (timeout<0)?INFINITE:(DWORD)timeout); - object_index = ret-WAIT_OBJECT_0; - if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) { - poll_dbg(" completed after wait"); - i = handle_to_index[object_index]; - _index = _fd_to_index_and_lock(fds[i].fd); - fds[i].revents = fds[i].events; - triggered++; - if (_index >= 0) { - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - } else if (ret == WAIT_TIMEOUT) { - poll_dbg(" timed out"); - triggered = 0; // 0 = timeout - } else { - errno = EIO; - triggered = -1; // error - } - } - -poll_exit: - if (handles_to_wait_on != NULL) { - free(handles_to_wait_on); - } - if (handle_to_index != NULL) { - free(handle_to_index); - } - return triggered; -} - -/* - * close a fake pipe fd - */ -int usbi_close(int fd) -{ - int _index; - int r = -1; - - CHECK_INIT_POLLING; - - _index = _fd_to_index_and_lock(fd); - - if (_index < 0) { - errno = EBADF; - } else { - free_overlapped(poll_fd[_index].overlapped); - poll_fd[_index] = INVALID_WINFD; - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - return r; -} - -/* - * synchronous write for fake "pipe" signaling - */ -ssize_t usbi_write(int fd, const void *buf, size_t count) -{ - int _index; - UNUSED(buf); - - CHECK_INIT_POLLING; - - if (count != sizeof(unsigned char)) { - usbi_err(NULL, "this function should only used for signaling"); - return -1; - } - - _index = _fd_to_index_and_lock(fd); - - if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) { - errno = EBADF; - if (_index >= 0) { - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - return -1; - } - - poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); - SetEvent(poll_fd[_index].overlapped->hEvent); - poll_fd[_index].overlapped->Internal = STATUS_WAIT_0; - // If two threads write on the pipe at the same time, we need to - // process two separate reads => use the overlapped as a counter - poll_fd[_index].overlapped->InternalHigh++; - - LeaveCriticalSection(&_poll_fd[_index].mutex); - return sizeof(unsigned char); -} - -/* - * synchronous read for fake "pipe" signaling - */ -ssize_t usbi_read(int fd, void *buf, size_t count) -{ - int _index; - ssize_t r = -1; - UNUSED(buf); - - CHECK_INIT_POLLING; - - if (count != sizeof(unsigned char)) { - usbi_err(NULL, "this function should only used for signaling"); - return -1; - } - - _index = _fd_to_index_and_lock(fd); - - if (_index < 0) { - errno = EBADF; - return -1; - } - - if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) { - usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError()); - errno = EIO; - goto out; - } - - poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); - poll_fd[_index].overlapped->InternalHigh--; - // Don't reset unless we don't have any more events to process - if (poll_fd[_index].overlapped->InternalHigh <= 0) { - ResetEvent(poll_fd[_index].overlapped->hEvent); - poll_fd[_index].overlapped->Internal = STATUS_PENDING; - } - - r = sizeof(unsigned char); - -out: - LeaveCriticalSection(&_poll_fd[_index].mutex); - return r; -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/poll_windows.h b/src/3rd_party-static/libusbx-1.0.16/libusb/os/poll_windows.h deleted file mode 100644 index deed206444..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/poll_windows.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Windows compat: POSIX compatibility wrapper - * Copyright © 2012-2013 RealVNC Ltd. - * Copyright © 2009-2010 Pete Batard <pete@akeo.ie> - * With contributions from Michael Plante, Orin Eman et al. - * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#pragma once - -#if defined(_MSC_VER) -// disable /W4 MSVC warnings that are benign -#pragma warning(disable:4127) // conditional expression is constant -#endif - -// Handle synchronous completion through the overlapped structure -#if !defined(STATUS_REPARSE) // reuse the REPARSE status code -#define STATUS_REPARSE ((LONG)0x00000104L) -#endif -#define STATUS_COMPLETED_SYNCHRONOUSLY STATUS_REPARSE -#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 DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2) - -enum windows_version { - WINDOWS_UNSUPPORTED, - WINDOWS_CE, - WINDOWS_XP, - WINDOWS_2003, // also includes XP 64 - WINDOWS_VISTA_AND_LATER, -}; -extern enum windows_version windows_version; - -#define MAX_FDS 256 - -#define POLLIN 0x0001 /* There is data to read */ -#define POLLPRI 0x0002 /* There is urgent data to read */ -#define POLLOUT 0x0004 /* Writing now will not block */ -#define POLLERR 0x0008 /* Error condition */ -#define POLLHUP 0x0010 /* Hung up */ -#define POLLNVAL 0x0020 /* Invalid request: fd not open */ - -struct pollfd { - int fd; /* file descriptor */ - short events; /* requested events */ - short revents; /* returned events */ -}; - -// access modes -enum rw_type { - RW_NONE, - RW_READ, - RW_WRITE, -}; - -// fd struct that can be used for polling on Windows -typedef int cancel_transfer(struct usbi_transfer *itransfer); - -struct winfd { - int fd; // what's exposed to libusb core - HANDLE handle; // what we need to attach overlapped to the I/O op, so we can poll it - OVERLAPPED* overlapped; // what will report our I/O status - struct usbi_transfer *itransfer; // Associated transfer, or NULL if completed - cancel_transfer *cancel_fn; // Function pointer to cancel transfer API - enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH) -}; -extern const struct winfd INVALID_WINFD; - -int usbi_pipe(int pipefd[2]); -int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout); -ssize_t usbi_write(int fd, const void *buf, size_t count); -ssize_t usbi_read(int fd, void *buf, size_t count); -int usbi_close(int fd); - -void init_polling(void); -void exit_polling(void); -struct winfd usbi_create_fd(HANDLE handle, int access_mode, - struct usbi_transfer *transfer, cancel_transfer *cancel_fn); -void usbi_free_fd(struct winfd* winfd); -struct winfd fd_to_winfd(int fd); -struct winfd handle_to_winfd(HANDLE handle); -struct winfd overlapped_to_winfd(OVERLAPPED* overlapped); - -/* - * Timeval operations - */ -#if defined(DDKBUILD) -#include <winsock.h> // defines timeval functions on DDK -#endif - -#if !defined(TIMESPEC_TO_TIMEVAL) -#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ - (tv)->tv_sec = (long)(ts)->tv_sec; \ - (tv)->tv_usec = (long)(ts)->tv_nsec / 1000; \ -} -#endif -#if !defined(timersub) -#define timersub(a, b, result) \ -do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ -} while (0) -#endif diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/threads_posix.c b/src/3rd_party-static/libusbx-1.0.16/libusb/os/threads_posix.c deleted file mode 100644 index 9769f58367..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/threads_posix.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * libusbx synchronization using POSIX Threads - * - * 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 - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#if defined(__linux__) || defined(__OpenBSD__) -# if defined(__linux__) -# define _GNU_SOURCE -# else -# define _BSD_SOURCE -# endif -# 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" - -int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr) -{ - int err; - pthread_mutexattr_t stack_attr; - if (!attr) { - attr = &stack_attr; - err = pthread_mutexattr_init(&stack_attr); - if (err != 0) - return err; - } - - /* mutexattr_settype requires _GNU_SOURCE or _XOPEN_SOURCE >= 500 on Linux */ - err = pthread_mutexattr_settype(attr, PTHREAD_MUTEX_RECURSIVE); - if (err != 0) - goto finish; - - err = pthread_mutex_init(mutex, attr); - -finish: - if (attr == &stack_attr) - pthread_mutexattr_destroy(&stack_attr); - - return err; -} - -int usbi_get_tid(void) -{ - int ret = -1; -#if 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; -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/threads_posix.h b/src/3rd_party-static/libusbx-1.0.16/libusb/os/threads_posix.h deleted file mode 100644 index 0b6a71a552..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/threads_posix.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * libusbx synchronization using POSIX Threads - * - * Copyright © 2010 Peter Stuge <peter@stuge.se> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LIBUSB_THREADS_POSIX_H -#define LIBUSB_THREADS_POSIX_H - -#include <pthread.h> - -#define usbi_mutex_static_t pthread_mutex_t -#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER -#define usbi_mutex_static_lock pthread_mutex_lock -#define usbi_mutex_static_unlock pthread_mutex_unlock - -#define usbi_mutex_t pthread_mutex_t -#define usbi_mutex_init pthread_mutex_init -#define usbi_mutex_lock pthread_mutex_lock -#define usbi_mutex_unlock pthread_mutex_unlock -#define usbi_mutex_trylock pthread_mutex_trylock -#define usbi_mutex_destroy pthread_mutex_destroy - -#define usbi_cond_t pthread_cond_t -#define usbi_cond_init pthread_cond_init -#define usbi_cond_wait pthread_cond_wait -#define usbi_cond_timedwait pthread_cond_timedwait -#define usbi_cond_broadcast pthread_cond_broadcast -#define usbi_cond_destroy pthread_cond_destroy -#define usbi_cond_signal pthread_cond_signal - -extern int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr); - -int usbi_get_tid(void); - -#endif /* LIBUSB_THREADS_POSIX_H */ diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/threads_windows.c b/src/3rd_party-static/libusbx-1.0.16/libusb/os/threads_windows.c deleted file mode 100644 index cad27e9ea0..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/threads_windows.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * libusbx synchronization on Microsoft Windows - * - * Copyright © 2010 Michael Plante <michael.plante@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> -#include <objbase.h> -#include <errno.h> -#include <stdarg.h> - -#include "libusbi.h" - -extern const uint64_t epoch_time; - -int usbi_mutex_init(usbi_mutex_t *mutex, - const usbi_mutexattr_t *attr) { - UNUSED(attr); - if(! mutex) return ((errno=EINVAL)); - *mutex = CreateMutex(NULL, FALSE, NULL); - if(!*mutex) return ((errno=ENOMEM)); - return 0; -} -int usbi_mutex_destroy(usbi_mutex_t *mutex) { - // It is not clear if CloseHandle failure is due to failure to unlock. - // If so, this should be errno=EBUSY. - if(!mutex || !CloseHandle(*mutex)) return ((errno=EINVAL)); - *mutex = NULL; - return 0; -} -int usbi_mutex_trylock(usbi_mutex_t *mutex) { - DWORD result; - if(!mutex) return ((errno=EINVAL)); - result = WaitForSingleObject(*mutex, 0); - if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) - return 0; // acquired (ToDo: check that abandoned is ok) - if(result == WAIT_TIMEOUT) - return ((errno=EBUSY)); - return ((errno=EINVAL)); // don't know how this would happen - // so don't know proper errno -} -int usbi_mutex_lock(usbi_mutex_t *mutex) { - DWORD result; - if(!mutex) return ((errno=EINVAL)); - result = WaitForSingleObject(*mutex, INFINITE); - if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) - return 0; // acquired (ToDo: check that abandoned is ok) - return ((errno=EINVAL)); // don't know how this would happen - // so don't know proper errno -} -int usbi_mutex_unlock(usbi_mutex_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - if(!ReleaseMutex(*mutex)) return ((errno=EPERM )); - return 0; -} - -int usbi_mutex_static_lock(usbi_mutex_static_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - while (InterlockedExchange((LONG *)mutex, 1) == 1) { - SleepEx(0, TRUE); - } - return 0; -} -int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - *mutex = 0; - return 0; -} - -int usbi_cond_init(usbi_cond_t *cond, - const usbi_condattr_t *attr) { - UNUSED(attr); - if(!cond) return ((errno=EINVAL)); - list_init(&cond->waiters ); - list_init(&cond->not_waiting); - return 0; -} -int usbi_cond_destroy(usbi_cond_t *cond) { - // This assumes no one is using this anymore. The check MAY NOT BE safe. - struct usbi_cond_perthread *pos, *next_pos = NULL; - if(!cond) return ((errno=EINVAL)); - if(!list_empty(&cond->waiters)) return ((errno=EBUSY )); // (!see above!) - list_for_each_entry_safe(pos, next_pos, &cond->not_waiting, list, struct usbi_cond_perthread) { - CloseHandle(pos->event); - list_del(&pos->list); - free(pos); - } - - return 0; -} - -int usbi_cond_broadcast(usbi_cond_t *cond) { - // Assumes mutex is locked; this is not in keeping with POSIX spec, but - // libusb does this anyway, so we simplify by not adding more sync - // primitives to the CV definition! - int fail = 0; - struct usbi_cond_perthread *pos; - if(!cond) return ((errno=EINVAL)); - list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread) { - if(!SetEvent(pos->event)) - fail = 1; - } - // The wait function will remove its respective item from the list. - return fail ? ((errno=EINVAL)) : 0; -} -int usbi_cond_signal(usbi_cond_t *cond) { - // Assumes mutex is locked; this is not in keeping with POSIX spec, but - // libusb does this anyway, so we simplify by not adding more sync - // primitives to the CV definition! - struct usbi_cond_perthread *pos; - if(!cond) return ((errno=EINVAL)); - if(list_empty(&cond->waiters)) return 0; // no one to wakeup. - pos = list_entry(&cond->waiters.next, struct usbi_cond_perthread, list); - // The wait function will remove its respective item from the list. - return SetEvent(pos->event) ? 0 : ((errno=EINVAL)); -} -__inline static int usbi_cond_intwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, - DWORD timeout_ms) { - struct usbi_cond_perthread *pos; - int found = 0, r; - DWORD r2,tid = GetCurrentThreadId(); - if(!cond || !mutex) return ((errno=EINVAL)); - list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) { - if(tid == pos->tid) { - found = 1; - break; - } - } - if(!found) { - pos = (struct usbi_cond_perthread*) calloc(1, sizeof(struct usbi_cond_perthread)); - if(!pos) return ((errno=ENOMEM)); // This errno is not POSIX-allowed. - pos->tid = tid; - pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset. - if(!pos->event) { - free(pos); - return ((errno=ENOMEM)); - } - list_add(&pos->list, &cond->not_waiting); - } - - list_del(&pos->list); // remove from not_waiting list. - list_add(&pos->list, &cond->waiters); - - r = usbi_mutex_unlock(mutex); - if(r) return r; - r2 = WaitForSingleObject(pos->event, timeout_ms); - r = usbi_mutex_lock(mutex); - if(r) return r; - - list_del(&pos->list); - list_add(&pos->list, &cond->not_waiting); - - if(r2 == WAIT_TIMEOUT) return ((errno=ETIMEDOUT)); - - return 0; -} -// N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot! -int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) { - return usbi_cond_intwait(cond, mutex, INFINITE); -} -int usbi_cond_timedwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, - const struct timespec *abstime) { - FILETIME filetime; - ULARGE_INTEGER rtime; - struct timeval targ_time, cur_time, delta_time; - struct timespec cur_time_ns; - DWORD millis; - - // GetSystemTimeAsFileTime() is not available on CE - SYSTEMTIME st; - GetSystemTime(&st); - SystemTimeToFileTime(&st, &filetime); - rtime.LowPart = filetime.dwLowDateTime; - rtime.HighPart = filetime.dwHighDateTime; - rtime.QuadPart -= epoch_time; - cur_time_ns.tv_sec = (long)(rtime.QuadPart / 10000000); - cur_time_ns.tv_nsec = (long)((rtime.QuadPart % 10000000)*100); - TIMESPEC_TO_TIMEVAL(&cur_time, &cur_time_ns); - - TIMESPEC_TO_TIMEVAL(&targ_time, abstime); - timersub(&targ_time, &cur_time, &delta_time); - if(delta_time.tv_sec < 0) // abstime already passed? - millis = 0; - else { - millis = delta_time.tv_usec/1000; - millis += delta_time.tv_sec *1000; - if (delta_time.tv_usec % 1000) // round up to next millisecond - millis++; - } - - return usbi_cond_intwait(cond, mutex, millis); -} - -int usbi_get_tid(void) { - return GetCurrentThreadId(); -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/threads_windows.h b/src/3rd_party-static/libusbx-1.0.16/libusb/os/threads_windows.h deleted file mode 100644 index df8a0eeb03..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/threads_windows.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * libusbx synchronization on Microsoft Windows - * - * Copyright © 2010 Michael Plante <michael.plante@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LIBUSB_THREADS_WINDOWS_H -#define LIBUSB_THREADS_WINDOWS_H - -#define usbi_mutex_static_t volatile LONG -#define USBI_MUTEX_INITIALIZER 0 - -#define usbi_mutex_t HANDLE - -struct usbi_cond_perthread { - struct list_head list; - DWORD tid; - HANDLE event; -}; -struct usbi_cond_t_ { - // Every time a thread touches the CV, it winds up in one of these lists. - // It stays there until the CV is destroyed, even if the thread - // terminates. - struct list_head waiters; - struct list_head not_waiting; -}; -typedef struct usbi_cond_t_ usbi_cond_t; - -// We *were* getting timespec from pthread.h: -#if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED)) -#define HAVE_STRUCT_TIMESPEC 1 -#define _TIMESPEC_DEFINED 1 -struct timespec { - long tv_sec; - long tv_nsec; -}; -#endif /* HAVE_STRUCT_TIMESPEC | _TIMESPEC_DEFINED */ - -// We *were* getting ETIMEDOUT from pthread.h: -#ifndef ETIMEDOUT -# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ -#endif - -#define usbi_mutexattr_t void -#define usbi_condattr_t void - -// all Windows mutexes are recursive -#define usbi_mutex_init_recursive(mutex, attr) usbi_mutex_init((mutex), (attr)) - -int usbi_mutex_static_lock(usbi_mutex_static_t *mutex); -int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex); - - -int usbi_mutex_init(usbi_mutex_t *mutex, - const usbi_mutexattr_t *attr); -int usbi_mutex_lock(usbi_mutex_t *mutex); -int usbi_mutex_unlock(usbi_mutex_t *mutex); -int usbi_mutex_trylock(usbi_mutex_t *mutex); -int usbi_mutex_destroy(usbi_mutex_t *mutex); - -int usbi_cond_init(usbi_cond_t *cond, - const usbi_condattr_t *attr); -int usbi_cond_destroy(usbi_cond_t *cond); -int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex); -int usbi_cond_timedwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, - const struct timespec *abstime); -int usbi_cond_broadcast(usbi_cond_t *cond); -int usbi_cond_signal(usbi_cond_t *cond); - -int usbi_get_tid(void); - -#endif /* LIBUSB_THREADS_WINDOWS_H */ diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/wince_usb.c b/src/3rd_party-static/libusbx-1.0.16/libusb/os/wince_usb.c deleted file mode 100644 index e4a66331e5..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/wince_usb.c +++ /dev/null @@ -1,1015 +0,0 @@ -/* - * 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; - } - } - // 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); - } - - // 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 %d: %s", windows_error_str(0)); - } - continue; - case 1: // time to quit - usbi_dbg("timer thread quitting"); - return 0; - } - } - usbi_dbg("ERROR: broken timer thread"); - return 1; -} - -static int 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, -}; diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/wince_usb.h b/src/3rd_party-static/libusbx-1.0.16/libusb/os/wince_usb.h deleted file mode 100644 index 3db9693a13..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/wince_usb.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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; -}; - diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/windows_common.h b/src/3rd_party-static/libusbx-1.0.16/libusb/os/windows_common.h deleted file mode 100644 index 1da72bd9f8..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/windows_common.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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) diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/windows_usb.c b/src/3rd_party-static/libusbx-1.0.16/libusb/os/windows_usb.c deleted file mode 100644 index 63357b1a21..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/windows_usb.c +++ /dev/null @@ -1,4393 +0,0 @@ -/* - * windows backend for libusbx 1.0 - * 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 - * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software - * Hash table functions adapted from glibc, by Ulrich Drepper et al. - * Major code testing contribution by Xiaofan Chen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> -#include <windows.h> -#include <setupapi.h> -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <process.h> -#include <stdio.h> -#include <inttypes.h> -#include <objbase.h> -#include <winioctl.h> - -#include "libusbi.h" -#include "poll_windows.h" -#include "windows_usb.h" - -// The 2 macros below are used in conjunction with safe loops. -#define LOOP_CHECK(fcall) { r=fcall; if (r != LIBUSB_SUCCESS) continue; } -#define LOOP_BREAK(err) { r=err; continue; } - -// Helper prototypes -static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian); -static int windows_clock_gettime(int clk_id, struct timespec *tp); -unsigned __stdcall windows_clock_gettime_threaded(void* param); -// Common calls -static int common_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface); - -// WinUSB-like API prototypes -static int winusbx_init(int sub_api, struct libusb_context *ctx); -static int winusbx_exit(int sub_api); -static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle); -static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle); -static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); -static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); -static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); -static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer); -static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer); -static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle); -static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); -// HID API prototypes -static int hid_init(int sub_api, struct libusb_context *ctx); -static int hid_exit(int sub_api); -static int hid_open(int sub_api, struct libusb_device_handle *dev_handle); -static void hid_close(int sub_api, struct libusb_device_handle *dev_handle); -static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); -static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); -static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); -static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer); -static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle); -static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); -// Composite API prototypes -static int composite_init(int sub_api, struct libusb_context *ctx); -static int composite_exit(int sub_api); -static int composite_open(int sub_api, struct libusb_device_handle *dev_handle); -static void composite_close(int sub_api, struct libusb_device_handle *dev_handle); -static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting); -static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface); -static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer); -static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer); -static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer); -static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer); -static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer); -static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle); -static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size); - - -// Global variables -uint64_t hires_frequency, hires_ticks_to_ps; -const uint64_t epoch_time = UINT64_C(116444736000000000); // 1970.01.01 00:00:000 in MS Filetime -enum windows_version windows_version = WINDOWS_UNSUPPORTED; -// Concurrency -static int concurrent_usage = -1; -usbi_mutex_t autoclaim_lock; -// Timer thread -// NB: index 0 is for monotonic and 1 is for the thread exit event -HANDLE timer_thread = NULL; -HANDLE timer_mutex = NULL; -struct timespec timer_tp; -volatile LONG request_count[2] = {0, 1}; // last one must be > 0 -HANDLE timer_request[2] = { NULL, NULL }; -HANDLE timer_response = NULL; -// API globals -#define CHECK_WINUSBX_AVAILABLE(sub_api) do { if (sub_api == SUB_API_NOTSET) sub_api = priv->sub_api; \ - if (!WinUSBX[sub_api].initialized) return LIBUSB_ERROR_ACCESS; } while(0) -static struct winusb_interface WinUSBX[SUB_API_MAX]; -const char* sub_api_name[SUB_API_MAX] = WINUSBX_DRV_NAMES; -bool api_hid_available = false; -#define CHECK_HID_AVAILABLE do { if (!api_hid_available) return LIBUSB_ERROR_ACCESS; } while (0) - -static inline BOOLEAN guid_eq(const GUID *guid1, const GUID *guid2) { - if ((guid1 != NULL) && (guid2 != NULL)) { - return (memcmp(guid1, guid2, sizeof(GUID)) == 0); - } - return false; -} - -#if defined(ENABLE_LOGGING) -static char* guid_to_string(const GUID* guid) -{ - static char guid_string[MAX_GUID_STRING_LENGTH]; - - if (guid == NULL) return NULL; - sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", - (unsigned int)guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], - guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); - return guid_string; -} -#endif - -/* - * Converts a windows error to human readable string - * uses retval as errorcode, or, if 0, use GetLastError() - */ -#if defined(ENABLE_LOGGING) -static char *windows_error_str(uint32_t retval) -{ -static char err_string[ERR_BUFFER_SIZE]; - - DWORD size; - ssize_t i; - uint32_t error_code, format_error; - - error_code = retval?retval:GetLastError(); - - safe_sprintf(err_string, ERR_BUFFER_SIZE, "[%u] ", error_code); - - size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &err_string[safe_strlen(err_string)], - ERR_BUFFER_SIZE - (DWORD)safe_strlen(err_string), NULL); - if (size == 0) { - format_error = GetLastError(); - if (format_error) - safe_sprintf(err_string, ERR_BUFFER_SIZE, - "Windows error code %u (FormatMessage error code %u)", error_code, format_error); - else - safe_sprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", error_code); - } else { - // Remove CR/LF terminators - for (i=safe_strlen(err_string)-1; (i>=0) && ((err_string[i]==0x0A) || (err_string[i]==0x0D)); i--) { - err_string[i] = 0; - } - } - return err_string; -} -#endif - -/* - * Sanitize Microsoft's paths: convert to uppercase, add prefix and fix backslashes. - * Return an allocated sanitized string or NULL on error. - */ -static char* sanitize_path(const char* path) -{ - const char root_prefix[] = "\\\\.\\"; - size_t j, size, root_size; - char* ret_path = NULL; - size_t add_root = 0; - - if (path == NULL) - return NULL; - - size = safe_strlen(path)+1; - root_size = sizeof(root_prefix)-1; - - // Microsoft indiscriminatly uses '\\?\', '\\.\', '##?#" or "##.#" for root prefixes. - if (!((size > 3) && (((path[0] == '\\') && (path[1] == '\\') && (path[3] == '\\')) || - ((path[0] == '#') && (path[1] == '#') && (path[3] == '#'))))) { - add_root = root_size; - size += add_root; - } - - if ((ret_path = (char*) calloc(size, 1)) == NULL) - return NULL; - - safe_strcpy(&ret_path[add_root], size-add_root, path); - - // Ensure consistancy with root prefix - for (j=0; j<root_size; j++) - ret_path[j] = root_prefix[j]; - - // Same goes for '\' and '#' after the root prefix. Ensure '#' is used - for(j=root_size; j<size; j++) { - ret_path[j] = (char)toupper((int)ret_path[j]); // Fix case too - if (ret_path[j] == '\\') - ret_path[j] = '#'; - } - - return ret_path; -} - -/* - * Cfgmgr32, OLE32 and SetupAPI DLL functions - */ -static int init_dlls(void) -{ - DLL_LOAD(Cfgmgr32.dll, CM_Get_Parent, TRUE); - DLL_LOAD(Cfgmgr32.dll, CM_Get_Child, TRUE); - DLL_LOAD(Cfgmgr32.dll, CM_Get_Sibling, TRUE); - DLL_LOAD(Cfgmgr32.dll, CM_Get_Device_IDA, TRUE); - // Prefixed to avoid conflict with header files - DLL_LOAD_PREFIXED(OLE32.dll, p, CLSIDFromString, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiGetClassDevsA, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiEnumDeviceInfo, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiEnumDeviceInterfaces, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiGetDeviceInterfaceDetailA, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiDestroyDeviceInfoList, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiOpenDevRegKey, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiGetDeviceRegistryPropertyA, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiOpenDeviceInterfaceRegKey, TRUE); - DLL_LOAD_PREFIXED(AdvAPI32.dll, p, RegQueryValueExW, TRUE); - DLL_LOAD_PREFIXED(AdvAPI32.dll, p, RegCloseKey, TRUE); - return LIBUSB_SUCCESS; -} - -/* - * enumerate interfaces for the whole USB class - * - * Parameters: - * dev_info: a pointer to a dev_info list - * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed) - * usb_class: the generic USB class for which to retrieve interface details - * index: zero based index of the interface in the device info list - * - * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA - * structure returned and call this function repeatedly using the same guid (with an - * incremented index starting at zero) until all interfaces have been returned. - */ -static bool get_devinfo_data(struct libusb_context *ctx, - HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const char* usb_class, unsigned _index) -{ - if (_index <= 0) { - *dev_info = pSetupDiGetClassDevsA(NULL, usb_class, NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES); - if (*dev_info == INVALID_HANDLE_VALUE) { - return false; - } - } - - dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); - if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) { - usbi_err(ctx, "Could not obtain device info data for index %u: %s", - _index, windows_error_str(0)); - } - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return false; - } - return true; -} - -/* - * enumerate interfaces for a specific GUID - * - * Parameters: - * dev_info: a pointer to a dev_info list - * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed) - * guid: the GUID for which to retrieve interface details - * index: zero based index of the interface in the device info list - * - * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA - * structure returned and call this function repeatedly using the same guid (with an - * incremented index starting at zero) until all interfaces have been returned. - */ -static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details(struct libusb_context *ctx, - HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID* guid, unsigned _index) -{ - SP_DEVICE_INTERFACE_DATA dev_interface_data; - SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; - DWORD size; - - if (_index <= 0) { - *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); - } - - if (dev_info_data != NULL) { - dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); - if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) { - usbi_err(ctx, "Could not obtain device info data for index %u: %s", - _index, windows_error_str(0)); - } - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; - } - } - - dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); - if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, guid, _index, &dev_interface_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) { - usbi_err(ctx, "Could not obtain interface data for index %u: %s", - _index, windows_error_str(0)); - } - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; - } - - // Read interface data (dummy + actual) to access the device path - if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) { - // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - usbi_err(ctx, "could not access interface data (dummy) for index %u: %s", - _index, windows_error_str(0)); - goto err_exit; - } - } else { - usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong."); - goto err_exit; - } - - if ((dev_interface_details = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) calloc(size, 1)) == NULL) { - usbi_err(ctx, "could not allocate interface data for index %u.", _index); - goto err_exit; - } - - dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); - if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, - dev_interface_details, size, &size, NULL)) { - usbi_err(ctx, "could not access interface data (actual) for index %u: %s", - _index, windows_error_str(0)); - } - - return dev_interface_details; - -err_exit: - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; -} - -/* For libusb0 filter */ -static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details_filter(struct libusb_context *ctx, - HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID* guid, unsigned _index, char* filter_path){ - SP_DEVICE_INTERFACE_DATA dev_interface_data; - SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; - DWORD size; - if (_index <= 0) { - *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); - } - if (dev_info_data != NULL) { - dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); - if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) { - usbi_err(ctx, "Could not obtain device info data for index %u: %s", - _index, windows_error_str(0)); - } - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; - } - } - dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); - if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, guid, _index, &dev_interface_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) { - usbi_err(ctx, "Could not obtain interface data for index %u: %s", - _index, windows_error_str(0)); - } - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; - } - // Read interface data (dummy + actual) to access the device path - if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) { - // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - usbi_err(ctx, "could not access interface data (dummy) for index %u: %s", - _index, windows_error_str(0)); - goto err_exit; - } - } else { - usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong."); - goto err_exit; - } - if ((dev_interface_details = malloc(size)) == NULL) { - usbi_err(ctx, "could not allocate interface data for index %u.", _index); - goto err_exit; - } - dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); - if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, - dev_interface_details, size, &size, NULL)) { - usbi_err(ctx, "could not access interface data (actual) for index %u: %s", - _index, windows_error_str(0)); - } - // [trobinso] lookup the libusb0 symbolic index. - if (dev_interface_details) { - HKEY hkey_device_interface=pSetupDiOpenDeviceInterfaceRegKey(*dev_info,&dev_interface_data,0,KEY_READ); - if (hkey_device_interface != INVALID_HANDLE_VALUE) { - DWORD libusb0_symboliclink_index=0; - DWORD value_length=sizeof(DWORD); - DWORD value_type=0; - LONG status; - status = pRegQueryValueExW(hkey_device_interface, L"LUsb0", NULL, &value_type, - (LPBYTE) &libusb0_symboliclink_index, &value_length); - if (status == ERROR_SUCCESS) { - if (libusb0_symboliclink_index < 256) { - // libusb0.sys is connected to this device instance. - // If the the device interface guid is {F9F3FF14-AE21-48A0-8A25-8011A7A931D9} then it's a filter. - safe_sprintf(filter_path, sizeof("\\\\.\\libusb0-0000"), "\\\\.\\libusb0-%04d", libusb0_symboliclink_index); - usbi_dbg("assigned libusb0 symbolic link %s", filter_path); - } else { - // libusb0.sys was connected to this device instance at one time; but not anymore. - } - } - pRegCloseKey(hkey_device_interface); - } - } - return dev_interface_details; -err_exit: - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL;} - -/* Hash table functions - modified From glibc 2.3.2: - [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 - [Knuth] The Art of Computer Programming, part 3 (6.4) */ -typedef struct htab_entry { - unsigned long used; - char* str; -} htab_entry; -htab_entry* htab_table = NULL; -usbi_mutex_t htab_write_mutex = NULL; -unsigned long htab_size, htab_filled; - -/* For the used double hash method the table size has to be a prime. To - correct the user given table size we need a prime test. This trivial - algorithm is adequate because the code is called only during init and - the number is likely to be small */ -static int isprime(unsigned long number) -{ - // no even number will be passed - unsigned int divider = 3; - - while((divider * divider < number) && (number % divider != 0)) - divider += 2; - - return (number % divider != 0); -} - -/* Before using the hash table we must allocate memory for it. - We allocate one element more as the found prime number says. - This is done for more effective indexing as explained in the - comment for the hash function. */ -static int htab_create(struct libusb_context *ctx, unsigned long nel) -{ - if (htab_table != NULL) { - usbi_err(ctx, "hash table already allocated"); - } - - // Create a mutex - usbi_mutex_init(&htab_write_mutex, NULL); - - // Change nel to the first prime number not smaller as nel. - nel |= 1; - while(!isprime(nel)) - nel += 2; - - htab_size = nel; - usbi_dbg("using %d entries hash table", nel); - htab_filled = 0; - - // allocate memory and zero out. - htab_table = (htab_entry*) calloc(htab_size + 1, sizeof(htab_entry)); - if (htab_table == NULL) { - usbi_err(ctx, "could not allocate space for hash table"); - return 0; - } - - return 1; -} - -/* After using the hash table it has to be destroyed. */ -static void htab_destroy(void) -{ - size_t i; - if (htab_table == NULL) { - return; - } - - for (i=0; i<htab_size; i++) { - if (htab_table[i].used) { - safe_free(htab_table[i].str); - } - } - usbi_mutex_destroy(&htab_write_mutex); - safe_free(htab_table); -} - -/* This is the search function. It uses double hashing with open addressing. - We use an trick to speed up the lookup. The table is created with one - more element available. This enables us to use the index zero special. - This index will never be used because we store the first hash index in - the field used where zero means not used. Every other value means used. - The used field can be used as a first fast comparison for equality of - the stored and the parameter value. This helps to prevent unnecessary - expensive calls of strcmp. */ -static unsigned long htab_hash(char* str) -{ - unsigned long hval, hval2; - unsigned long idx; - unsigned long r = 5381; - int c; - char* sz = str; - - if (str == NULL) - return 0; - - // Compute main hash value (algorithm suggested by Nokia) - while ((c = *sz++) != 0) - r = ((r << 5) + r) + c; - if (r == 0) - ++r; - - // compute table hash: simply take the modulus - hval = r % htab_size; - if (hval == 0) - ++hval; - - // Try the first index - idx = hval; - - if (htab_table[idx].used) { - if ( (htab_table[idx].used == hval) - && (safe_strcmp(str, htab_table[idx].str) == 0) ) { - // existing hash - return idx; - } - usbi_dbg("hash collision ('%s' vs '%s')", str, htab_table[idx].str); - - // Second hash function, as suggested in [Knuth] - hval2 = 1 + hval % (htab_size - 2); - - do { - // Because size is prime this guarantees to step through all available indexes - if (idx <= hval2) { - idx = htab_size + idx - hval2; - } else { - idx -= hval2; - } - - // If we visited all entries leave the loop unsuccessfully - if (idx == hval) { - break; - } - - // If entry is found use it. - if ( (htab_table[idx].used == hval) - && (safe_strcmp(str, htab_table[idx].str) == 0) ) { - return idx; - } - } - while (htab_table[idx].used); - } - - // Not found => New entry - - // If the table is full return an error - if (htab_filled >= htab_size) { - usbi_err(NULL, "hash table is full (%d entries)", htab_size); - return 0; - } - - // Concurrent threads might be storing the same entry at the same time - // (eg. "simultaneous" enums from different threads) => use a mutex - usbi_mutex_lock(&htab_write_mutex); - // Just free any previously allocated string (which should be the same as - // new one). The possibility of concurrent threads storing a collision - // string (same hash, different string) at the same time is extremely low - safe_free(htab_table[idx].str); - htab_table[idx].used = hval; - htab_table[idx].str = (char*) malloc(safe_strlen(str)+1); - if (htab_table[idx].str == NULL) { - usbi_err(NULL, "could not duplicate string for hash table"); - usbi_mutex_unlock(&htab_write_mutex); - return 0; - } - memcpy(htab_table[idx].str, str, safe_strlen(str)+1); - ++htab_filled; - usbi_mutex_unlock(&htab_write_mutex); - - return idx; -} - -/* - * Returns the session ID of a device's nth level ancestor - * If there's no device at the nth level, return 0 - */ -static unsigned long get_ancestor_session_id(DWORD devinst, unsigned level) -{ - DWORD parent_devinst; - unsigned long session_id = 0; - char* sanitized_path = NULL; - char path[MAX_PATH_LENGTH]; - unsigned i; - - if (level < 1) return 0; - for (i = 0; i<level; i++) { - if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS) { - return 0; - } - devinst = parent_devinst; - } - if (CM_Get_Device_IDA(devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) { - return 0; - } - // TODO: (post hotplug): try without sanitizing - sanitized_path = sanitize_path(path); - if (sanitized_path == NULL) { - return 0; - } - session_id = htab_hash(sanitized_path); - safe_free(sanitized_path); - return session_id; -} - -/* - * Populate the endpoints addresses of the device_priv interface helper structs - */ -static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - int i, r; - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct libusb_config_descriptor *conf_desc; - const struct libusb_interface_descriptor *if_desc; - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - - r = libusb_get_config_descriptor(dev_handle->dev, 0, &conf_desc); - if (r != LIBUSB_SUCCESS) { - usbi_warn(ctx, "could not read config descriptor: error %d", r); - return r; - } - - if_desc = &conf_desc->interface[iface].altsetting[altsetting]; - safe_free(priv->usb_interface[iface].endpoint); - - if (if_desc->bNumEndpoints == 0) { - usbi_dbg("no endpoints found for interface %d", iface); - return LIBUSB_SUCCESS; - } - - priv->usb_interface[iface].endpoint = (uint8_t*) malloc(if_desc->bNumEndpoints); - if (priv->usb_interface[iface].endpoint == NULL) { - return LIBUSB_ERROR_NO_MEM; - } - - priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints; - for (i=0; i<if_desc->bNumEndpoints; i++) { - priv->usb_interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress; - usbi_dbg("(re)assigned endpoint %02X to interface %d", priv->usb_interface[iface].endpoint[i], iface); - } - libusb_free_config_descriptor(conf_desc); - - // Extra init may be required to configure endpoints - return priv->apib->configure_endpoints(SUB_API_NOTSET, dev_handle, iface); -} - -// Lookup for a match in the list of API driver names -// return -1 if not found, driver match number otherwise -static int get_sub_api(char* driver, int api){ - int i; - const char sep_str[2] = {LIST_SEPARATOR, 0}; - char *tok, *tmp_str; - size_t len = safe_strlen(driver); - - if (len == 0) return SUB_API_NOTSET; - tmp_str = (char*) calloc(len+1, 1); - if (tmp_str == NULL) return SUB_API_NOTSET; - memcpy(tmp_str, driver, len+1); - tok = strtok(tmp_str, sep_str); - while (tok != NULL) { - for (i=0; i<usb_api_backend[api].nb_driver_names; i++) { - if (safe_stricmp(tok, usb_api_backend[api].driver_name_list[i]) == 0) { - free(tmp_str); - return i; - } - } - tok = strtok(NULL, sep_str); - } - free (tmp_str); - return SUB_API_NOTSET; -} - -/* - * auto-claiming and auto-release helper functions - */ -static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type) -{ - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv( - transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int current_interface = *interface_number; - int r = LIBUSB_SUCCESS; - - switch(api_type) { - case USB_API_WINUSBX: - case USB_API_HID: - break; - default: - return LIBUSB_ERROR_INVALID_PARAM; - } - - usbi_mutex_lock(&autoclaim_lock); - if (current_interface < 0) // No serviceable interface was found - { - for (current_interface=0; current_interface<USB_MAXINTERFACES; current_interface++) { - // Must claim an interface of the same API type - if ( (priv->usb_interface[current_interface].apib->id == api_type) - && (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS) ) { - usbi_dbg("auto-claimed interface %d for control request", current_interface); - if (handle_priv->autoclaim_count[current_interface] != 0) { - usbi_warn(ctx, "program assertion failed - autoclaim_count was nonzero"); - } - handle_priv->autoclaim_count[current_interface]++; - break; - } - } - if (current_interface == USB_MAXINTERFACES) { - usbi_err(ctx, "could not auto-claim any interface"); - r = LIBUSB_ERROR_NOT_FOUND; - } - } else { - // If we have a valid interface that was autoclaimed, we must increment - // its autoclaim count so that we can prevent an early release. - if (handle_priv->autoclaim_count[current_interface] != 0) { - handle_priv->autoclaim_count[current_interface]++; - } - } - usbi_mutex_unlock(&autoclaim_lock); - - *interface_number = current_interface; - return r; - -} - -static void auto_release(struct usbi_transfer *itransfer) -{ - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - libusb_device_handle *dev_handle = transfer->dev_handle; - struct windows_device_handle_priv* handle_priv = _device_handle_priv(dev_handle); - int r; - - usbi_mutex_lock(&autoclaim_lock); - if (handle_priv->autoclaim_count[transfer_priv->interface_number] > 0) { - handle_priv->autoclaim_count[transfer_priv->interface_number]--; - if (handle_priv->autoclaim_count[transfer_priv->interface_number] == 0) { - r = libusb_release_interface(dev_handle, transfer_priv->interface_number); - if (r == LIBUSB_SUCCESS) { - usbi_dbg("auto-released interface %d", transfer_priv->interface_number); - } else { - usbi_dbg("failed to auto-release interface %d (%s)", - transfer_priv->interface_number, libusb_error_name((enum libusb_error)r)); - } - } - } - usbi_mutex_unlock(&autoclaim_lock); -} - -/* - * init: libusbx backend init function - * - * This function enumerates the HCDs (Host Controller Drivers) and populates our private HCD list - * In our implementation, we equate Windows' "HCD" to libusbx's "bus". Note that bus is zero indexed. - * HCDs are not expected to change after init (might not hold true for hot pluggable USB PCI card?) - */ -static int windows_init(struct libusb_context *ctx) -{ - int i, r = LIBUSB_ERROR_OTHER; - OSVERSIONINFO os_version; - HANDLE semaphore; - char sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID) - - sprintf(sem_name, "libusb_init%08X", (unsigned int)GetCurrentProcessId()&0xFFFFFFFF); - semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); - if (semaphore == NULL) { - usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_MEM; - } - - // A successful wait brings our semaphore count to 0 (unsignaled) - // => any concurent wait stalls until the semaphore's release - if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { - usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0)); - CloseHandle(semaphore); - return LIBUSB_ERROR_NO_MEM; - } - - // NB: concurrent usage supposes that init calls are equally balanced with - // exit calls. If init is called more than exit, we will not exit properly - if ( ++concurrent_usage == 0 ) { // First init? - // Detect OS version - memset(&os_version, 0, sizeof(OSVERSIONINFO)); - os_version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - windows_version = WINDOWS_UNSUPPORTED; - if ((GetVersionEx(&os_version) != 0) && (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT)) { - if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 1)) { - windows_version = WINDOWS_XP; - } else if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 2)) { - windows_version = WINDOWS_2003; // also includes XP 64 - } else if (os_version.dwMajorVersion >= 6) { - windows_version = WINDOWS_VISTA_AND_LATER; - } - } - if (windows_version == WINDOWS_UNSUPPORTED) { - usbi_err(ctx, "This version of Windows is NOT supported"); - r = LIBUSB_ERROR_NOT_SUPPORTED; - goto init_exit; - } - - // We need a lock for proper auto-release - usbi_mutex_init(&autoclaim_lock, NULL); - - // Initialize pollable file descriptors - init_polling(); - - // Load DLL imports - if (init_dlls() != LIBUSB_SUCCESS) { - usbi_err(ctx, "could not resolve DLL functions"); - return LIBUSB_ERROR_NOT_FOUND; - } - - // Initialize the low level APIs (we don't care about errors at this stage) - for (i=0; i<USB_API_MAX; i++) { - usb_api_backend[i].init(SUB_API_NOTSET, ctx); - } - - // Because QueryPerformanceCounter might report different values when - // running on different cores, we create a separate thread for the timer - // calls, which we glue to the first core always to prevent timing discrepancies. - r = LIBUSB_ERROR_NO_MEM; - for (i = 0; i < 2; i++) { - timer_request[i] = CreateEvent(NULL, TRUE, FALSE, NULL); - if (timer_request[i] == NULL) { - usbi_err(ctx, "could not create timer request event %d - aborting", i); - goto init_exit; - } - } - timer_response = CreateSemaphore(NULL, 0, MAX_TIMER_SEMAPHORES, NULL); - if (timer_response == NULL) { - usbi_err(ctx, "could not create timer response semaphore - aborting"); - goto init_exit; - } - timer_mutex = CreateMutex(NULL, FALSE, NULL); - if (timer_mutex == NULL) { - usbi_err(ctx, "could not create timer mutex - aborting"); - goto init_exit; - } - timer_thread = (HANDLE)_beginthreadex(NULL, 0, windows_clock_gettime_threaded, NULL, 0, NULL); - if (timer_thread == NULL) { - usbi_err(ctx, "Unable to create timer thread - aborting"); - goto init_exit; - } - SetThreadAffinityMask(timer_thread, 0); - - // Create a hash table to store session ids. Second parameter is better if prime - htab_create(ctx, HTAB_SIZE); - } - // At this stage, either we went through full init successfully, or didn't need to - r = LIBUSB_SUCCESS; - -init_exit: // Holds semaphore here. - if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed? - if (timer_thread) { - SetEvent(timer_request[1]); // actually the signal to quit the thread. - if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) { - usbi_warn(ctx, "could not wait for timer thread to quit"); - TerminateThread(timer_thread, 1); // shouldn't happen, but we're destroying - // all objects it might have held anyway. - } - CloseHandle(timer_thread); - timer_thread = NULL; - } - for (i = 0; i < 2; i++) { - if (timer_request[i]) { - CloseHandle(timer_request[i]); - timer_request[i] = NULL; - } - } - if (timer_response) { - CloseHandle(timer_response); - timer_response = NULL; - } - if (timer_mutex) { - CloseHandle(timer_mutex); - timer_mutex = NULL; - } - htab_destroy(); - } - - if (r != LIBUSB_SUCCESS) - --concurrent_usage; // Not expected to call libusb_exit if we failed. - - ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 - CloseHandle(semaphore); - return r; -} - -/* - * HCD (root) hubs need to have their device descriptor manually populated - * - * Note that, like Microsoft does in the device manager, we populate the - * Vendor and Device ID for HCD hubs with the ones from the PCI HCD device. - */ -static int force_hcd_device_descriptor(struct libusb_device *dev) -{ - struct windows_device_priv *parent_priv, *priv = _device_priv(dev); - struct libusb_context *ctx = DEVICE_CTX(dev); - int vid, pid; - - dev->num_configurations = 1; - priv->dev_descriptor.bLength = sizeof(USB_DEVICE_DESCRIPTOR); - priv->dev_descriptor.bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE; - priv->dev_descriptor.bNumConfigurations = 1; - priv->active_config = 1; - - if (priv->parent_dev == NULL) { - usbi_err(ctx, "program assertion failed - HCD hub has no parent"); - return LIBUSB_ERROR_NO_DEVICE; - } - parent_priv = _device_priv(priv->parent_dev); - if (sscanf(parent_priv->path, "\\\\.\\PCI#VEN_%04x&DEV_%04x%*s", &vid, &pid) == 2) { - priv->dev_descriptor.idVendor = (uint16_t)vid; - priv->dev_descriptor.idProduct = (uint16_t)pid; - } else { - usbi_warn(ctx, "could not infer VID/PID of HCD hub from '%s'", parent_priv->path); - priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub - priv->dev_descriptor.idProduct = 1; - } - return LIBUSB_SUCCESS; -} - -/* - * fetch and cache all the config descriptors through I/O - */ -static int cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle, char* device_id) -{ - DWORD size, ret_size; - struct libusb_context *ctx = DEVICE_CTX(dev); - struct windows_device_priv *priv = _device_priv(dev); - int r; - uint8_t i; - - USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request - PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request - PUSB_CONFIGURATION_DESCRIPTOR cd_data = NULL; - - if (dev->num_configurations == 0) - return LIBUSB_ERROR_INVALID_PARAM; - - priv->config_descriptor = (unsigned char**) calloc(dev->num_configurations, sizeof(unsigned char*)); - if (priv->config_descriptor == NULL) - return LIBUSB_ERROR_NO_MEM; - for (i=0; i<dev->num_configurations; i++) - priv->config_descriptor[i] = NULL; - - for (i=0, r=LIBUSB_SUCCESS; ; i++) - { - // safe loop: release all dynamic resources - safe_free(cd_buf_actual); - - // safe loop: end of loop condition - if ((i >= dev->num_configurations) || (r != LIBUSB_SUCCESS)) - break; - - size = sizeof(USB_CONFIGURATION_DESCRIPTOR_SHORT); - memset(&cd_buf_short, 0, size); - - cd_buf_short.req.ConnectionIndex = (ULONG)priv->port; - cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; - cd_buf_short.req.SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR; - cd_buf_short.req.SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i; - cd_buf_short.req.SetupPacket.wIndex = i; - cd_buf_short.req.SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST)); - - // Dummy call to get the required data size. Initial failures are reported as info rather - // than error as they can occur for non-penalizing situations, such as with some hubs. - if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &cd_buf_short, size, - &cd_buf_short, size, &ret_size, NULL)) { - usbi_info(ctx, "could not access configuration descriptor (dummy) for '%s': %s", device_id, windows_error_str(0)); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - if ((ret_size != size) || (cd_buf_short.data.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))) { - usbi_info(ctx, "unexpected configuration descriptor size (dummy) for '%s'.", device_id); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - size = sizeof(USB_DESCRIPTOR_REQUEST) + cd_buf_short.data.wTotalLength; - if ((cd_buf_actual = (PUSB_DESCRIPTOR_REQUEST) calloc(1, size)) == NULL) { - usbi_err(ctx, "could not allocate configuration descriptor buffer for '%s'.", device_id); - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - memset(cd_buf_actual, 0, size); - - // Actual call - cd_buf_actual->ConnectionIndex = (ULONG)priv->port; - cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; - cd_buf_actual->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR; - cd_buf_actual->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i; - cd_buf_actual->SetupPacket.wIndex = i; - cd_buf_actual->SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST)); - - if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, cd_buf_actual, size, - cd_buf_actual, size, &ret_size, NULL)) { - usbi_err(ctx, "could not access configuration descriptor (actual) for '%s': %s", device_id, windows_error_str(0)); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR*)cd_buf_actual+sizeof(USB_DESCRIPTOR_REQUEST)); - - if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.data.wTotalLength)) { - usbi_err(ctx, "unexpected configuration descriptor size (actual) for '%s'.", device_id); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - if (cd_data->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE) { - usbi_err(ctx, "not a configuration descriptor for '%s'", device_id); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - usbi_dbg("cached config descriptor %d (bConfigurationValue=%d, %d bytes)", - i, cd_data->bConfigurationValue, cd_data->wTotalLength); - - // Cache the descriptor - priv->config_descriptor[i] = (unsigned char*) malloc(cd_data->wTotalLength); - if (priv->config_descriptor[i] == NULL) - return LIBUSB_ERROR_NO_MEM; - memcpy(priv->config_descriptor[i], cd_data, cd_data->wTotalLength); - } - return LIBUSB_SUCCESS; -} - -/* - * Populate a libusbx device structure - */ -static int init_device(struct libusb_device* dev, struct libusb_device* parent_dev, - uint8_t port_number, char* device_id, DWORD devinst) -{ - HANDLE handle; - DWORD size; - USB_NODE_CONNECTION_INFORMATION_EX conn_info; - struct windows_device_priv *priv, *parent_priv; - struct libusb_context *ctx = DEVICE_CTX(dev); - struct libusb_device* tmp_dev; - unsigned i; - - if ((dev == NULL) || (parent_dev == NULL)) { - return LIBUSB_ERROR_NOT_FOUND; - } - priv = _device_priv(dev); - parent_priv = _device_priv(parent_dev); - if (parent_priv->apib->id != USB_API_HUB) { - usbi_warn(ctx, "parent for device '%s' is not a hub", device_id); - return LIBUSB_ERROR_NOT_FOUND; - } - - // It is possible for the parent hub not to have been initialized yet - // If that's the case, lookup the ancestors to set the bus number - if (parent_dev->bus_number == 0) { - for (i=2; ; i++) { - tmp_dev = usbi_get_device_by_session_id(ctx, get_ancestor_session_id(devinst, i)); - if (tmp_dev == NULL) break; - if (tmp_dev->bus_number != 0) { - usbi_dbg("got bus number from ancestor #%d", i); - parent_dev->bus_number = tmp_dev->bus_number; - break; - } - } - } - if (parent_dev->bus_number == 0) { - usbi_err(ctx, "program assertion failed: unable to find ancestor bus number for '%s'", device_id); - return LIBUSB_ERROR_NOT_FOUND; - } - dev->bus_number = parent_dev->bus_number; - priv->port = port_number; - dev->port_number = port_number; - priv->depth = parent_priv->depth + 1; - priv->parent_dev = parent_dev; - dev->parent_dev = libusb_ref_device(parent_dev); - - // If the device address is already set, we can stop here - if (dev->device_address != 0) { - return LIBUSB_SUCCESS; - } - memset(&conn_info, 0, sizeof(conn_info)); - if (priv->depth != 0) { // Not a HCD hub - handle = CreateFileA(parent_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, NULL); - if (handle == INVALID_HANDLE_VALUE) { - usbi_warn(ctx, "could not open hub %s: %s", parent_priv->path, windows_error_str(0)); - return LIBUSB_ERROR_ACCESS; - } - size = sizeof(conn_info); - conn_info.ConnectionIndex = (ULONG)port_number; - if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, size, - &conn_info, size, &size, NULL)) { - usbi_warn(ctx, "could not get node connection information for device '%s': %s", - device_id, windows_error_str(0)); - safe_closehandle(handle); - return LIBUSB_ERROR_NO_DEVICE; - } - if (conn_info.ConnectionStatus == NoDeviceConnected) { - usbi_err(ctx, "device '%s' is no longer connected!", device_id); - safe_closehandle(handle); - return LIBUSB_ERROR_NO_DEVICE; - } - memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR)); - dev->num_configurations = priv->dev_descriptor.bNumConfigurations; - priv->active_config = conn_info.CurrentConfigurationValue; - usbi_dbg("found %d configurations (active conf: %d)", dev->num_configurations, priv->active_config); - // If we can't read the config descriptors, just set the number of confs to zero - if (cache_config_descriptors(dev, handle, device_id) != LIBUSB_SUCCESS) { - dev->num_configurations = 0; - priv->dev_descriptor.bNumConfigurations = 0; - } - safe_closehandle(handle); - - if (conn_info.DeviceAddress > UINT8_MAX) { - usbi_err(ctx, "program assertion failed: device address overflow"); - } - dev->device_address = (uint8_t)conn_info.DeviceAddress + 1; - if (dev->device_address == 1) { - usbi_err(ctx, "program assertion failed: device address collision with root hub"); - } - switch (conn_info.Speed) { - case 0: dev->speed = LIBUSB_SPEED_LOW; break; - case 1: dev->speed = LIBUSB_SPEED_FULL; break; - case 2: dev->speed = LIBUSB_SPEED_HIGH; break; - case 3: dev->speed = LIBUSB_SPEED_SUPER; break; - default: - usbi_warn(ctx, "Got unknown device speed %d", conn_info.Speed); - break; - } - } else { - dev->device_address = 1; // root hubs are set to use device number 1 - force_hcd_device_descriptor(dev); - } - - usbi_sanitize_device(dev); - - usbi_dbg("(bus: %d, addr: %d, depth: %d, port: %d): '%s'", - dev->bus_number, dev->device_address, priv->depth, priv->port, device_id); - - return LIBUSB_SUCCESS; -} - -// Returns the api type, or 0 if not found/unsupported -static void get_api_type(struct libusb_context *ctx, HDEVINFO *dev_info, - SP_DEVINFO_DATA *dev_info_data, int *api, int *sub_api) -{ - // Precedence for filter drivers vs driver is in the order of this array - struct driver_lookup lookup[3] = { - {"\0\0", SPDRP_SERVICE, "driver"}, - {"\0\0", SPDRP_UPPERFILTERS, "upper filter driver"}, - {"\0\0", SPDRP_LOWERFILTERS, "lower filter driver"} - }; - DWORD size, reg_type; - unsigned k, l; - int i, j; - - *api = USB_API_UNSUPPORTED; - *sub_api = SUB_API_NOTSET; - // Check the service & filter names to know the API we should use - for (k=0; k<3; k++) { - if (pSetupDiGetDeviceRegistryPropertyA(*dev_info, dev_info_data, lookup[k].reg_prop, - ®_type, (BYTE*)lookup[k].list, MAX_KEY_LENGTH, &size)) { - // Turn the REG_SZ SPDRP_SERVICE into REG_MULTI_SZ - if (lookup[k].reg_prop == SPDRP_SERVICE) { - // our buffers are MAX_KEY_LENGTH+1 so we can overflow if needed - lookup[k].list[safe_strlen(lookup[k].list)+1] = 0; - } - // MULTI_SZ is a pain to work with. Turn it into something much more manageable - // NB: none of the driver names we check against contain LIST_SEPARATOR, - // (currently ';'), so even if an unsuported one does, it's not an issue - for (l=0; (lookup[k].list[l] != 0) || (lookup[k].list[l+1] != 0); l++) { - if (lookup[k].list[l] == 0) { - lookup[k].list[l] = LIST_SEPARATOR; - } - } - usbi_dbg("%s(s): %s", lookup[k].designation, lookup[k].list); - } else { - if (GetLastError() != ERROR_INVALID_DATA) { - usbi_dbg("could not access %s: %s", lookup[k].designation, windows_error_str(0)); - } - lookup[k].list[0] = 0; - } - } - - for (i=1; i<USB_API_MAX; i++) { - for (k=0; k<3; k++) { - j = get_sub_api(lookup[k].list, i); - if (j >= 0) { - usbi_dbg("matched %s name against %s API", - lookup[k].designation, (i!=USB_API_WINUSBX)?usb_api_backend[i].designation:sub_api_name[j]); - *api = i; - *sub_api = j; - return; - } - } - } -} - -static int set_composite_interface(struct libusb_context* ctx, struct libusb_device* dev, - char* dev_interface_path, char* device_id, int api, int sub_api) -{ - unsigned i; - struct windows_device_priv *priv = _device_priv(dev); - int interface_number; - - if (priv->apib->id != USB_API_COMPOSITE) { - usbi_err(ctx, "program assertion failed: '%s' is not composite", device_id); - return LIBUSB_ERROR_NO_DEVICE; - } - - // Because MI_## are not necessarily in sequential order (some composite - // devices will have only MI_00 & MI_03 for instance), we retrieve the actual - // interface number from the path's MI value - interface_number = 0; - for (i=0; device_id[i] != 0; ) { - if ( (device_id[i++] == 'M') && (device_id[i++] == 'I') - && (device_id[i++] == '_') ) { - interface_number = (device_id[i++] - '0')*10; - interface_number += device_id[i] - '0'; - break; - } - } - - if (device_id[i] == 0) { - usbi_warn(ctx, "failure to read interface number for %s. Using default value %d", - device_id, interface_number); - } - - if (priv->usb_interface[interface_number].path != NULL) { - if (api == USB_API_HID) { - // HID devices can have multiple collections (COL##) for each MI_## interface - usbi_dbg("interface[%d] already set - ignoring HID collection: %s", - interface_number, device_id); - return LIBUSB_ERROR_ACCESS; - } - // In other cases, just use the latest data - safe_free(priv->usb_interface[interface_number].path); - } - - usbi_dbg("interface[%d] = %s", interface_number, dev_interface_path); - priv->usb_interface[interface_number].path = dev_interface_path; - priv->usb_interface[interface_number].apib = &usb_api_backend[api]; - priv->usb_interface[interface_number].sub_api = sub_api; - if ((api == USB_API_HID) && (priv->hid == NULL)) { - priv->hid = (struct hid_device_priv*) calloc(1, sizeof(struct hid_device_priv)); - if (priv->hid == NULL) - return LIBUSB_ERROR_NO_MEM; - } - - return LIBUSB_SUCCESS; -} - -static int set_hid_interface(struct libusb_context* ctx, struct libusb_device* dev, - char* dev_interface_path) -{ - int i; - struct windows_device_priv *priv = _device_priv(dev); - - if (priv->hid == NULL) { - usbi_err(ctx, "program assertion failed: parent is not HID"); - return LIBUSB_ERROR_NO_DEVICE; - } - if (priv->hid->nb_interfaces == USB_MAXINTERFACES) { - usbi_err(ctx, "program assertion failed: max USB interfaces reached for HID device"); - return LIBUSB_ERROR_NO_DEVICE; - } - for (i=0; i<priv->hid->nb_interfaces; i++) { - if (safe_strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) { - usbi_dbg("interface[%d] already set to %s", i, dev_interface_path); - return LIBUSB_SUCCESS; - } - } - - priv->usb_interface[priv->hid->nb_interfaces].path = dev_interface_path; - priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID]; - usbi_dbg("interface[%d] = %s", priv->hid->nb_interfaces, dev_interface_path); - priv->hid->nb_interfaces++; - return LIBUSB_SUCCESS; -} - -/* - * get_device_list: libusbx backend device enumeration function - */ -static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) -{ - struct discovered_devs *discdevs; - HDEVINFO dev_info = { 0 }; - const char* usb_class[] = {"USB", "NUSB3", "IUSB3"}; - SP_DEVINFO_DATA dev_info_data = { 0 }; - SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; - GUID hid_guid; -#define MAX_ENUM_GUIDS 64 - const GUID* guid[MAX_ENUM_GUIDS]; -#define HCD_PASS 0 -#define HUB_PASS 1 -#define GEN_PASS 2 -#define DEV_PASS 3 -#define HID_PASS 4 - int r = LIBUSB_SUCCESS; - int api, sub_api; - size_t class_index = 0; - unsigned int nb_guids, pass, i, j, ancestor; - char path[MAX_PATH_LENGTH]; - char strbuf[MAX_PATH_LENGTH]; - struct libusb_device *dev, *parent_dev; - struct windows_device_priv *priv, *parent_priv; - char* dev_interface_path = NULL; - char* dev_id_path = NULL; - unsigned long session_id; - DWORD size, reg_type, port_nr, install_state; - HKEY key; - WCHAR guid_string_w[MAX_GUID_STRING_LENGTH]; - GUID* if_guid; - LONG s; - // Keep a list of newly allocated devs to unref - libusb_device** unref_list; - unsigned int unref_size = 64; - unsigned int unref_cur = 0; - - // PASS 1 : (re)enumerate HCDs (allows for HCD hotplug) - // PASS 2 : (re)enumerate HUBS - // PASS 3 : (re)enumerate generic USB devices (including driverless) - // and list additional USB device interface GUIDs to explore - // PASS 4 : (re)enumerate master USB devices that have a device interface - // PASS 5+: (re)enumerate device interfaced GUIDs (including HID) and - // set the device interfaces. - - // Init the GUID table - guid[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER; - guid[HUB_PASS] = &GUID_DEVINTERFACE_USB_HUB; - guid[GEN_PASS] = NULL; - guid[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE; - HidD_GetHidGuid(&hid_guid); - guid[HID_PASS] = &hid_guid; - nb_guids = HID_PASS+1; - - unref_list = (libusb_device**) calloc(unref_size, sizeof(libusb_device*)); - if (unref_list == NULL) { - return LIBUSB_ERROR_NO_MEM; - } - - for (pass = 0; ((pass < nb_guids) && (r == LIBUSB_SUCCESS)); pass++) { -//#define ENUM_DEBUG -#ifdef ENUM_DEBUG - const char *passname[] = { "HCD", "HUB", "GEN", "DEV", "HID", "EXT" }; - usbi_dbg("\n#### PROCESSING %ss %s", passname[(pass<=HID_PASS)?pass:HID_PASS+1], - (pass!=GEN_PASS)?guid_to_string(guid[pass]):""); -#endif - for (i = 0; ; i++) { - // safe loop: free up any (unprotected) dynamic resource - // NB: this is always executed before breaking the loop - safe_free(dev_interface_details); - safe_free(dev_interface_path); - safe_free(dev_id_path); - priv = parent_priv = NULL; - dev = parent_dev = NULL; - - // Safe loop: end of loop conditions - if (r != LIBUSB_SUCCESS) { - break; - } - if ((pass == HCD_PASS) && (i == UINT8_MAX)) { - usbi_warn(ctx, "program assertion failed - found more than %d buses, skipping the rest.", UINT8_MAX); - break; - } - if (pass != GEN_PASS) { - // Except for GEN, all passes deal with device interfaces - dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, guid[pass], i); - if (dev_interface_details == NULL) { - break; - } else { - dev_interface_path = sanitize_path(dev_interface_details->DevicePath); - if (dev_interface_path == NULL) { - usbi_warn(ctx, "could not sanitize device interface path for '%s'", dev_interface_details->DevicePath); - continue; - } - } - } else { - // Workaround for a Nec/Renesas USB 3.0 driver bug where root hubs are - // being listed under the "NUSB3" PnP Symbolic Name rather than "USB". - // The Intel USB 3.0 driver behaves similar, but uses "IUSB3" - for (; class_index < ARRAYSIZE(usb_class); class_index++) { - if (get_devinfo_data(ctx, &dev_info, &dev_info_data, usb_class[class_index], i)) - break; - i = 0; - } - if (class_index >= ARRAYSIZE(usb_class)) - break; - } - - // Read the Device ID path. This is what we'll use as UID - // Note that if the device is plugged in a different port or hub, the Device ID changes - if (CM_Get_Device_IDA(dev_info_data.DevInst, path, sizeof(path), 0) != CR_SUCCESS) { - usbi_warn(ctx, "could not read the device id path for devinst %X, skipping", - dev_info_data.DevInst); - continue; - } - dev_id_path = sanitize_path(path); - if (dev_id_path == NULL) { - usbi_warn(ctx, "could not sanitize device id path for devinst %X, skipping", - dev_info_data.DevInst); - continue; - } -#ifdef ENUM_DEBUG - usbi_dbg("PRO: %s", dev_id_path); -#endif - - // The SPDRP_ADDRESS for USB devices is the device port number on the hub - port_nr = 0; - if ((pass >= HUB_PASS) && (pass <= GEN_PASS)) { - if ( (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ADDRESS, - ®_type, (BYTE*)&port_nr, 4, &size)) - || (size != 4) ) { - usbi_warn(ctx, "could not retrieve port number for device '%s', skipping: %s", - dev_id_path, windows_error_str(0)); - continue; - } - } - - // Set API to use or get additional data from generic pass - api = USB_API_UNSUPPORTED; - sub_api = SUB_API_NOTSET; - switch (pass) { - case HCD_PASS: - break; - case GEN_PASS: - // We use the GEN pass to detect driverless devices... - size = sizeof(strbuf); - if (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_DRIVER, - ®_type, (BYTE*)strbuf, size, &size)) { - usbi_info(ctx, "The following device has no driver: '%s'", dev_id_path); - usbi_info(ctx, "libusbx will not be able to access it."); - } - // ...and to add the additional device interface GUIDs - key = pSetupDiOpenDevRegKey(dev_info, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); - if (key != INVALID_HANDLE_VALUE) { - size = sizeof(guid_string_w); - s = pRegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, ®_type, - (BYTE*)guid_string_w, &size); - pRegCloseKey(key); - if (s == ERROR_SUCCESS) { - if (nb_guids >= MAX_ENUM_GUIDS) { - // If this assert is ever reported, grow a GUID table dynamically - usbi_err(ctx, "program assertion failed: too many GUIDs"); - LOOP_BREAK(LIBUSB_ERROR_OVERFLOW); - } - if_guid = (GUID*) calloc(1, sizeof(GUID)); - pCLSIDFromString(guid_string_w, if_guid); - guid[nb_guids++] = if_guid; - usbi_dbg("extra GUID: %s", guid_to_string(if_guid)); - } - } - break; - case HID_PASS: - api = USB_API_HID; - break; - default: - // Get the API type (after checking that the driver installation is OK) - if ( (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_INSTALL_STATE, - ®_type, (BYTE*)&install_state, 4, &size)) - || (size != 4) ){ - usbi_warn(ctx, "could not detect installation state of driver for '%s': %s", - dev_id_path, windows_error_str(0)); - } else if (install_state != 0) { - usbi_warn(ctx, "driver for device '%s' is reporting an issue (code: %d) - skipping", - dev_id_path, install_state); - continue; - } - get_api_type(ctx, &dev_info, &dev_info_data, &api, &sub_api); - break; - } - - // Find parent device (for the passes that need it) - switch (pass) { - case HCD_PASS: - case DEV_PASS: - case HUB_PASS: - break; - default: - // Go through the ancestors until we see a face we recognize - parent_dev = NULL; - for (ancestor = 1; parent_dev == NULL; ancestor++) { - session_id = get_ancestor_session_id(dev_info_data.DevInst, ancestor); - if (session_id == 0) { - break; - } - parent_dev = usbi_get_device_by_session_id(ctx, session_id); - } - if (parent_dev == NULL) { - usbi_dbg("unlisted ancestor for '%s' (non USB HID, newly connected, etc.) - ignoring", dev_id_path); - continue; - } - parent_priv = _device_priv(parent_dev); - // virtual USB devices are also listed during GEN - don't process these yet - if ( (pass == GEN_PASS) && (parent_priv->apib->id != USB_API_HUB) ) { - continue; - } - break; - } - - // Create new or match existing device, using the (hashed) device_id as session id - if (pass <= DEV_PASS) { // For subsequent passes, we'll lookup the parent - // These are the passes that create "new" devices - session_id = htab_hash(dev_id_path); - dev = usbi_get_device_by_session_id(ctx, session_id); - if (dev == NULL) { - if (pass == DEV_PASS) { - // This can occur if the OS only reports a newly plugged device after we started enum - usbi_warn(ctx, "'%s' was only detected in late pass (newly connected device?)" - " - ignoring", dev_id_path); - continue; - } - usbi_dbg("allocating new device for session [%X]", session_id); - if ((dev = usbi_alloc_device(ctx, session_id)) == NULL) { - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - windows_device_priv_init(dev); - // Keep track of devices that need unref - unref_list[unref_cur++] = dev; - if (unref_cur >= unref_size) { - unref_size += 64; - unref_list = usbi_reallocf(unref_list, unref_size*sizeof(libusb_device*)); - if (unref_list == NULL) { - usbi_err(ctx, "could not realloc list for unref - aborting."); - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - } - } else { - usbi_dbg("found existing device for session [%X] (%d.%d)", - session_id, dev->bus_number, dev->device_address); - } - priv = _device_priv(dev); - } - - // Setup device - switch (pass) { - case HCD_PASS: - dev->bus_number = (uint8_t)(i + 1); // bus 0 is reserved for disconnected - dev->device_address = 0; - dev->num_configurations = 0; - priv->apib = &usb_api_backend[USB_API_HUB]; - priv->sub_api = SUB_API_NOTSET; - priv->depth = UINT8_MAX; // Overflow to 0 for HCD Hubs - priv->path = dev_interface_path; dev_interface_path = NULL; - break; - case HUB_PASS: - case DEV_PASS: - // If the device has already been setup, don't do it again - if (priv->path != NULL) - break; - // Take care of API initialization - priv->path = dev_interface_path; dev_interface_path = NULL; - priv->apib = &usb_api_backend[api]; - priv->sub_api = sub_api; - switch(api) { - case USB_API_COMPOSITE: - case USB_API_HUB: - break; - case USB_API_HID: - priv->hid = calloc(1, sizeof(struct hid_device_priv)); - if (priv->hid == NULL) { - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - priv->hid->nb_interfaces = 0; - break; - default: - // For other devices, the first interface is the same as the device - priv->usb_interface[0].path = (char*) calloc(safe_strlen(priv->path)+1, 1); - if (priv->usb_interface[0].path != NULL) { - safe_strcpy(priv->usb_interface[0].path, safe_strlen(priv->path)+1, priv->path); - } else { - usbi_warn(ctx, "could not duplicate interface path '%s'", priv->path); - } - // The following is needed if we want API calls to work for both simple - // and composite devices. - for(j=0; j<USB_MAXINTERFACES; j++) { - priv->usb_interface[j].apib = &usb_api_backend[api]; - } - break; - } - break; - case GEN_PASS: - r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_id_path, dev_info_data.DevInst); - if (r == LIBUSB_SUCCESS) { - // Append device to the list of discovered devices - discdevs = discovered_devs_append(*_discdevs, dev); - if (!discdevs) { - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - *_discdevs = discdevs; - } else if (r == LIBUSB_ERROR_NO_DEVICE) { - // This can occur if the device was disconnected but Windows hasn't - // refreshed its enumeration yet - in that case, we ignore the device - r = LIBUSB_SUCCESS; - } - break; - default: // HID_PASS and later - if (parent_priv->apib->id == USB_API_HID) { - usbi_dbg("setting HID interface for [%lX]:", parent_dev->session_data); - r = set_hid_interface(ctx, parent_dev, dev_interface_path); - if (r != LIBUSB_SUCCESS) LOOP_BREAK(r); - dev_interface_path = NULL; - } else if (parent_priv->apib->id == USB_API_COMPOSITE) { - usbi_dbg("setting composite interface for [%lX]:", parent_dev->session_data); - switch (set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id_path, api, sub_api)) { - case LIBUSB_SUCCESS: - dev_interface_path = NULL; - break; - case LIBUSB_ERROR_ACCESS: - // interface has already been set => make sure dev_interface_path is freed then - break; - default: - LOOP_BREAK(r); - break; - } - } - break; - } - } - } - - // Free any additional GUIDs - for (pass = HID_PASS+1; pass < nb_guids; pass++) { - safe_free(guid[pass]); - } - - // Unref newly allocated devs - for (i=0; i<unref_cur; i++) { - safe_unref_device(unref_list[i]); - } - safe_free(unref_list); - - return r; -} - -/* - * exit: libusbx backend deinitialization function - */ -static void windows_exit(void) -{ - int i; - HANDLE semaphore; - char sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID) - - sprintf(sem_name, "libusb_init%08X", (unsigned int)GetCurrentProcessId()&0xFFFFFFFF); - semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); - if (semaphore == NULL) { - return; - } - - // A successful wait brings our semaphore count to 0 (unsignaled) - // => any concurent wait stalls until the semaphore release - if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { - CloseHandle(semaphore); - return; - } - - // Only works if exits and inits are balanced exactly - if (--concurrent_usage < 0) { // Last exit - for (i=0; i<USB_API_MAX; i++) { - usb_api_backend[i].exit(SUB_API_NOTSET); - } - exit_polling(); - - if (timer_thread) { - SetEvent(timer_request[1]); // actually the signal to quit the thread. - if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) { - usbi_dbg("could not wait for timer thread to quit"); - TerminateThread(timer_thread, 1); - } - CloseHandle(timer_thread); - timer_thread = NULL; - } - for (i = 0; i < 2; i++) { - if (timer_request[i]) { - CloseHandle(timer_request[i]); - timer_request[i] = NULL; - } - } - if (timer_response) { - CloseHandle(timer_response); - timer_response = NULL; - } - if (timer_mutex) { - CloseHandle(timer_mutex); - timer_mutex = NULL; - } - htab_destroy(); - } - - ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 - CloseHandle(semaphore); -} - -static int windows_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) -{ - struct windows_device_priv *priv = _device_priv(dev); - - memcpy(buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH); - *host_endian = 0; - - return LIBUSB_SUCCESS; -} - -static int windows_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) -{ - struct windows_device_priv *priv = _device_priv(dev); - PUSB_CONFIGURATION_DESCRIPTOR config_header; - size_t size; - - // config index is zero based - if (config_index >= dev->num_configurations) - return LIBUSB_ERROR_INVALID_PARAM; - - if ((priv->config_descriptor == NULL) || (priv->config_descriptor[config_index] == NULL)) - return LIBUSB_ERROR_NOT_FOUND; - - config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptor[config_index]; - - size = min(config_header->wTotalLength, len); - memcpy(buffer, priv->config_descriptor[config_index], size); - *host_endian = 0; - - return size; -} - -/* - * return the cached copy of the active config descriptor - */ -static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) -{ - struct windows_device_priv *priv = _device_priv(dev); - - if (priv->active_config == 0) - return LIBUSB_ERROR_NOT_FOUND; - - // config index is zero based - return windows_get_config_descriptor(dev, (uint8_t)(priv->active_config-1), buffer, len, host_endian); -} - -static int windows_open(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - - if (priv->apib == NULL) { - usbi_err(ctx, "program assertion failed - device is not initialized"); - return LIBUSB_ERROR_NO_DEVICE; - } - - return priv->apib->open(SUB_API_NOTSET, dev_handle); -} - -static void windows_close(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - priv->apib->close(SUB_API_NOTSET, dev_handle); -} - -static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - if (priv->active_config == 0) { - *config = 0; - return LIBUSB_ERROR_NOT_FOUND; - } - - *config = priv->active_config; - return LIBUSB_SUCCESS; -} - -/* - * from http://msdn.microsoft.com/en-us/library/ms793522.aspx: "The port driver - * does not currently expose a service that allows higher-level drivers to set - * the configuration." - */ -static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - int r = LIBUSB_SUCCESS; - - if (config >= USB_MAXCONFIG) - return LIBUSB_ERROR_INVALID_PARAM; - - r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_OUT | - LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, - LIBUSB_REQUEST_SET_CONFIGURATION, (uint16_t)config, - 0, NULL, 0, 1000); - - if (r == LIBUSB_SUCCESS) { - priv->active_config = (uint8_t)config; - } - return r; -} - -static int windows_claim_interface(struct libusb_device_handle *dev_handle, int iface) -{ - int r = LIBUSB_SUCCESS; - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - if (iface >= USB_MAXINTERFACES) - return LIBUSB_ERROR_INVALID_PARAM; - - safe_free(priv->usb_interface[iface].endpoint); - priv->usb_interface[iface].nb_endpoints= 0; - - r = priv->apib->claim_interface(SUB_API_NOTSET, dev_handle, iface); - - if (r == LIBUSB_SUCCESS) { - r = windows_assign_endpoints(dev_handle, iface, 0); - } - - return r; -} - -static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - int r = LIBUSB_SUCCESS; - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - safe_free(priv->usb_interface[iface].endpoint); - priv->usb_interface[iface].nb_endpoints= 0; - - r = priv->apib->set_interface_altsetting(SUB_API_NOTSET, dev_handle, iface, altsetting); - - if (r == LIBUSB_SUCCESS) { - r = windows_assign_endpoints(dev_handle, iface, altsetting); - } - - return r; -} - -static int windows_release_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - return priv->apib->release_interface(SUB_API_NOTSET, dev_handle, iface); -} - -static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - return priv->apib->clear_halt(SUB_API_NOTSET, dev_handle, endpoint); -} - -static int windows_reset_device(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - return priv->apib->reset_device(SUB_API_NOTSET, dev_handle); -} - -// The 3 functions below are unlikely to ever get supported on Windows -static int windows_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int windows_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int windows_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static void windows_destroy_device(struct libusb_device *dev) -{ - windows_device_priv_release(dev); -} - -static void windows_clear_transfer_priv(struct usbi_transfer *itransfer) -{ - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - - usbi_free_fd(&transfer_priv->pollable_fd); - safe_free(transfer_priv->hid_buffer); - // When auto claim is in use, attempt to release the auto-claimed interface - auto_release(itransfer); -} - -static int submit_bulk_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int r; - - r = priv->apib->submit_bulk_transfer(SUB_API_NOTSET, itransfer); - if (r != LIBUSB_SUCCESS) { - return r; - } - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, - (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT)); - - itransfer->flags |= USBI_TRANSFER_UPDATED_FDS; - return LIBUSB_SUCCESS; -} - -static int submit_iso_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int r; - - r = priv->apib->submit_iso_transfer(SUB_API_NOTSET, itransfer); - if (r != LIBUSB_SUCCESS) { - return r; - } - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, - (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT)); - - itransfer->flags |= USBI_TRANSFER_UPDATED_FDS; - return LIBUSB_SUCCESS; -} - -static int submit_control_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int r; - - r = priv->apib->submit_control_transfer(SUB_API_NOTSET, itransfer); - if (r != LIBUSB_SUCCESS) { - return r; - } - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN); - - itransfer->flags |= USBI_TRANSFER_UPDATED_FDS; - return LIBUSB_SUCCESS; - -} - -static int windows_submit_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return submit_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - if (IS_XFEROUT(transfer) && - transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) - return LIBUSB_ERROR_NOT_SUPPORTED; - return submit_bulk_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return submit_iso_transfer(itransfer); - default: - usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static int windows_abort_control(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->apib->abort_control(SUB_API_NOTSET, itransfer); -} - -static int windows_abort_transfers(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->apib->abort_transfers(SUB_API_NOTSET, itransfer); -} - -static int windows_cancel_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return windows_abort_control(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return windows_abort_transfers(itransfer); - default: - usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static void windows_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int status, istatus; - - usbi_dbg("handling I/O completion with errcode %d, size %d", io_result, io_size); - - switch(io_result) { - case NO_ERROR: - status = priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size); - break; - case ERROR_GEN_FAILURE: - usbi_dbg("detected endpoint stall"); - status = LIBUSB_TRANSFER_STALL; - break; - case ERROR_SEM_TIMEOUT: - usbi_dbg("detected semaphore timeout"); - status = LIBUSB_TRANSFER_TIMED_OUT; - break; - case ERROR_OPERATION_ABORTED: - istatus = priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size); - if (istatus != LIBUSB_TRANSFER_COMPLETED) { - usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus); - } - 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 %d: %s", io_result, windows_error_str(0)); - status = LIBUSB_TRANSFER_ERROR; - break; - } - windows_clear_transfer_priv(itransfer); // Cancel polling - usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status); -} - -static void windows_handle_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - windows_transfer_callback (itransfer, io_result, io_size); - break; - default: - usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); - } -} - -static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready) -{ - struct windows_transfer_priv* transfer_priv = NULL; - POLL_NFDS_TYPE i = 0; - bool found = false; - struct usbi_transfer *transfer; - DWORD io_size, io_result; - - usbi_mutex_lock(&ctx->open_devs_lock); - for (i = 0; i < nfds && num_ready > 0; i++) { - - usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents); - - if (!fds[i].revents) { - continue; - } - - num_ready--; - - // Because a Windows OVERLAPPED is used for poll emulation, - // a pollable fd is created and stored with each transfer - usbi_mutex_lock(&ctx->flying_transfers_lock); - list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { - transfer_priv = usbi_transfer_get_os_priv(transfer); - if (transfer_priv->pollable_fd.fd == fds[i].fd) { - found = true; - break; - } - } - usbi_mutex_unlock(&ctx->flying_transfers_lock); - - if (found) { - // Handle async requests that completed synchronously first - if (HasOverlappedIoCompletedSync(transfer_priv->pollable_fd.overlapped)) { - io_result = NO_ERROR; - io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh; - // Regular async overlapped - } else if (GetOverlappedResult(transfer_priv->pollable_fd.handle, - transfer_priv->pollable_fd.overlapped, &io_size, false)) { - io_result = NO_ERROR; - } else { - io_result = GetLastError(); - } - usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd); - // let handle_callback free the event using the transfer wfd - // If you don't use the transfer wfd, you run a risk of trying to free a - // newly allocated wfd that took the place of the one from the transfer. - windows_handle_callback(transfer, io_result, io_size); - } else { - usbi_err(ctx, "could not find a matching transfer for fd %x", fds[i]); - return LIBUSB_ERROR_NOT_FOUND; - } - } - - usbi_mutex_unlock(&ctx->open_devs_lock); - return LIBUSB_SUCCESS; -} - -/* - * Monotonic and real time functions - */ -unsigned __stdcall windows_clock_gettime_threaded(void* param) -{ - LARGE_INTEGER hires_counter, li_frequency; - LONG nb_responses; - int timer_index; - - // Init - find out if we have access to a monotonic (hires) timer - if (!QueryPerformanceFrequency(&li_frequency)) { - usbi_dbg("no hires timer available on this platform"); - hires_frequency = 0; - hires_ticks_to_ps = UINT64_C(0); - } else { - hires_frequency = li_frequency.QuadPart; - // The hires frequency can go as high as 4 GHz, so we'll use a conversion - // to picoseconds to compute the tv_nsecs part in clock_gettime - hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency; - usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency); - } - - // Main loop - wait for requests - while (1) { - timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0; - if ( (timer_index != 0) && (timer_index != 1) ) { - usbi_dbg("failure to wait on requests: %s", windows_error_str(0)); - continue; - } - if (request_count[timer_index] == 0) { - // Request already handled - ResetEvent(timer_request[timer_index]); - // There's still a possiblity that a thread sends a request between the - // time we test request_count[] == 0 and we reset the event, in which case - // the request would be ignored. The simple solution to that is to test - // request_count again and process requests if non zero. - if (request_count[timer_index] == 0) - continue; - } - switch (timer_index) { - case 0: - WaitForSingleObject(timer_mutex, INFINITE); - // Requests to this thread are for hires always - if (QueryPerformanceCounter(&hires_counter) != 0) { - timer_tp.tv_sec = (long)(hires_counter.QuadPart / hires_frequency); - timer_tp.tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency)/1000) * hires_ticks_to_ps); - } else { - // Fallback to real-time if we can't get monotonic value - // Note that real-time clock does not wait on the mutex or this thread. - windows_clock_gettime(USBI_CLOCK_REALTIME, &timer_tp); - } - ReleaseMutex(timer_mutex); - - nb_responses = InterlockedExchange((LONG*)&request_count[0], 0); - if ( (nb_responses) - && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0) ) { - usbi_dbg("unable to release timer semaphore %d: %s", windows_error_str(0)); - } - continue; - case 1: // time to quit - usbi_dbg("timer thread quitting"); - return 0; - } - } -} - -static int windows_clock_gettime(int clk_id, struct timespec *tp) -{ - FILETIME filetime; - ULARGE_INTEGER rtime; - DWORD r; - switch(clk_id) { - case USBI_CLOCK_MONOTONIC: - if (hires_frequency != 0) { - while (1) { - InterlockedIncrement((LONG*)&request_count[0]); - SetEvent(timer_request[0]); - r = WaitForSingleObject(timer_response, TIMER_REQUEST_RETRY_MS); - switch(r) { - case WAIT_OBJECT_0: - WaitForSingleObject(timer_mutex, INFINITE); - *tp = timer_tp; - ReleaseMutex(timer_mutex); - return LIBUSB_SUCCESS; - case WAIT_TIMEOUT: - usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?"); - break; // Retry until successful - default: - usbi_dbg("WaitForSingleObject failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_OTHER; - } - } - } - // Fall through and return real-time if monotonic was not detected @ timer init - case USBI_CLOCK_REALTIME: - // We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx - // with a predef epoch_time to have an epoch that starts at 1970.01.01 00:00 - // Note however that our resolution is bounded by the Windows system time - // functions and is at best of the order of 1 ms (or, usually, worse) - GetSystemTimeAsFileTime(&filetime); - rtime.LowPart = filetime.dwLowDateTime; - rtime.HighPart = filetime.dwHighDateTime; - rtime.QuadPart -= epoch_time; - tp->tv_sec = (long)(rtime.QuadPart / 10000000); - tp->tv_nsec = (long)((rtime.QuadPart % 10000000)*100); - return LIBUSB_SUCCESS; - default: - return LIBUSB_ERROR_INVALID_PARAM; - } -} - - -// NB: MSVC6 does not support named initializers. -const struct usbi_os_backend windows_backend = { - "Windows", - USBI_CAP_HAS_HID_ACCESS, - windows_init, - windows_exit, - - windows_get_device_list, - NULL, /* hotplug_poll */ - windows_open, - windows_close, - - windows_get_device_descriptor, - windows_get_active_config_descriptor, - windows_get_config_descriptor, - NULL, /* get_config_descriptor_by_value() */ - - windows_get_configuration, - windows_set_configuration, - windows_claim_interface, - windows_release_interface, - - windows_set_interface_altsetting, - windows_clear_halt, - windows_reset_device, - - windows_kernel_driver_active, - windows_detach_kernel_driver, - windows_attach_kernel_driver, - - windows_destroy_device, - - windows_submit_transfer, - windows_cancel_transfer, - windows_clear_transfer_priv, - - windows_handle_events, - - windows_clock_gettime, -#if defined(USBI_TIMERFD_AVAILABLE) - NULL, -#endif - sizeof(struct windows_device_priv), - sizeof(struct windows_device_handle_priv), - sizeof(struct windows_transfer_priv), - 0, -}; - - -/* - * USB API backends - */ -static int unsupported_init(int sub_api, struct libusb_context *ctx) { - return LIBUSB_SUCCESS; -} -static int unsupported_exit(int sub_api) { - return LIBUSB_SUCCESS; -} -static int unsupported_open(int sub_api, struct libusb_device_handle *dev_handle) { - PRINT_UNSUPPORTED_API(open); -} -static void unsupported_close(int sub_api, struct libusb_device_handle *dev_handle) { - usbi_dbg("unsupported API call for 'close'"); -} -static int unsupported_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface) { - PRINT_UNSUPPORTED_API(configure_endpoints); -} -static int unsupported_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) { - PRINT_UNSUPPORTED_API(claim_interface); -} -static int unsupported_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) { - PRINT_UNSUPPORTED_API(set_interface_altsetting); -} -static int unsupported_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) { - PRINT_UNSUPPORTED_API(release_interface); -} -static int unsupported_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) { - PRINT_UNSUPPORTED_API(clear_halt); -} -static int unsupported_reset_device(int sub_api, struct libusb_device_handle *dev_handle) { - PRINT_UNSUPPORTED_API(reset_device); -} -static int unsupported_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(submit_bulk_transfer); -} -static int unsupported_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(submit_iso_transfer); -} -static int unsupported_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(submit_control_transfer); -} -static int unsupported_abort_control(int sub_api, struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(abort_control); -} -static int unsupported_abort_transfers(int sub_api, struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(abort_transfers); -} -static int unsupported_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) { - PRINT_UNSUPPORTED_API(copy_transfer_data); -} -static int common_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface) { - return LIBUSB_SUCCESS; -} -// These names must be uppercase -const char* hub_driver_names[] = {"USBHUB", "USBHUB3", "NUSB3HUB", "RUSB3HUB", "FLXHCIH", "TIHUB3", "ETRONHUB3", "VIAHUB3", "ASMTHUB3", "IUSB3HUB"}; -const char* composite_driver_names[] = {"USBCCGP"}; -const char* winusbx_driver_names[] = WINUSBX_DRV_NAMES; -const char* hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"}; -const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { - { - USB_API_UNSUPPORTED, - "Unsupported API", - NULL, - 0, - unsupported_init, - unsupported_exit, - unsupported_open, - unsupported_close, - unsupported_configure_endpoints, - unsupported_claim_interface, - unsupported_set_interface_altsetting, - unsupported_release_interface, - unsupported_clear_halt, - unsupported_reset_device, - unsupported_submit_bulk_transfer, - unsupported_submit_iso_transfer, - unsupported_submit_control_transfer, - unsupported_abort_control, - unsupported_abort_transfers, - unsupported_copy_transfer_data, - }, { - USB_API_HUB, - "HUB API", - hub_driver_names, - ARRAYSIZE(hub_driver_names), - unsupported_init, - unsupported_exit, - unsupported_open, - unsupported_close, - unsupported_configure_endpoints, - unsupported_claim_interface, - unsupported_set_interface_altsetting, - unsupported_release_interface, - unsupported_clear_halt, - unsupported_reset_device, - unsupported_submit_bulk_transfer, - unsupported_submit_iso_transfer, - unsupported_submit_control_transfer, - unsupported_abort_control, - unsupported_abort_transfers, - unsupported_copy_transfer_data, - }, { - USB_API_COMPOSITE, - "Composite API", - composite_driver_names, - ARRAYSIZE(composite_driver_names), - composite_init, - composite_exit, - composite_open, - composite_close, - common_configure_endpoints, - composite_claim_interface, - composite_set_interface_altsetting, - composite_release_interface, - composite_clear_halt, - composite_reset_device, - composite_submit_bulk_transfer, - composite_submit_iso_transfer, - composite_submit_control_transfer, - composite_abort_control, - composite_abort_transfers, - composite_copy_transfer_data, - }, { - USB_API_WINUSBX, - "WinUSB-like APIs", - winusbx_driver_names, - ARRAYSIZE(winusbx_driver_names), - winusbx_init, - winusbx_exit, - winusbx_open, - winusbx_close, - winusbx_configure_endpoints, - winusbx_claim_interface, - winusbx_set_interface_altsetting, - winusbx_release_interface, - winusbx_clear_halt, - winusbx_reset_device, - winusbx_submit_bulk_transfer, - unsupported_submit_iso_transfer, - winusbx_submit_control_transfer, - winusbx_abort_control, - winusbx_abort_transfers, - winusbx_copy_transfer_data, - }, { - USB_API_HID, - "HID API", - hid_driver_names, - ARRAYSIZE(hid_driver_names), - hid_init, - hid_exit, - hid_open, - hid_close, - common_configure_endpoints, - hid_claim_interface, - hid_set_interface_altsetting, - hid_release_interface, - hid_clear_halt, - hid_reset_device, - hid_submit_bulk_transfer, - unsupported_submit_iso_transfer, - hid_submit_control_transfer, - hid_abort_transfers, - hid_abort_transfers, - hid_copy_transfer_data, - }, -}; - - -/* - * WinUSB-like (WinUSB, libusb0/libusbK through libusbk DLL) API functions - */ -#define WinUSBX_Set(fn) do { if (native_winusb) WinUSBX[i].fn = (WinUsb_##fn##_t) GetProcAddress(h, "WinUsb_" #fn); \ - else pLibK_GetProcAddress((PVOID*)&WinUSBX[i].fn, i, KUSB_FNID_##fn); } while (0) - -static int winusbx_init(int sub_api, struct libusb_context *ctx) -{ - HMODULE h = NULL; - bool native_winusb = false; - int i; - KLIB_VERSION LibK_Version; - LibK_GetProcAddress_t pLibK_GetProcAddress = NULL; - LibK_GetVersion_t pLibK_GetVersion = NULL; - - h = GetModuleHandleA("libusbK"); - if (h == NULL) { - h = LoadLibraryA("libusbK"); - } - if (h == NULL) { - usbi_info(ctx, "libusbK DLL is not available, will use native WinUSB"); - h = GetModuleHandleA("WinUSB"); - if (h == NULL) { - h = LoadLibraryA("WinUSB"); - } if (h == NULL) { - usbi_warn(ctx, "WinUSB DLL is not available either,\n" - "you will not be able to access devices outside of enumeration"); - return LIBUSB_ERROR_NOT_FOUND; - } - } else { - usbi_dbg("using libusbK DLL for universal access"); - pLibK_GetVersion = (LibK_GetVersion_t) GetProcAddress(h, "LibK_GetVersion"); - if (pLibK_GetVersion != NULL) { - pLibK_GetVersion(&LibK_Version); - usbi_dbg("libusbK version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor, - LibK_Version.Micro, LibK_Version.Nano); - } - pLibK_GetProcAddress = (LibK_GetProcAddress_t) GetProcAddress(h, "LibK_GetProcAddress"); - if (pLibK_GetProcAddress == NULL) { - usbi_err(ctx, "LibK_GetProcAddress() not found in libusbK DLL"); - return LIBUSB_ERROR_NOT_FOUND; - } - } - native_winusb = (pLibK_GetProcAddress == NULL); - for (i=SUB_API_LIBUSBK; i<SUB_API_MAX; i++) { - WinUSBX_Set(AbortPipe); - WinUSBX_Set(ControlTransfer); - WinUSBX_Set(FlushPipe); - WinUSBX_Set(Free); - WinUSBX_Set(GetAssociatedInterface); - WinUSBX_Set(GetCurrentAlternateSetting); - WinUSBX_Set(GetDescriptor); - WinUSBX_Set(GetOverlappedResult); - WinUSBX_Set(GetPipePolicy); - WinUSBX_Set(GetPowerPolicy); - WinUSBX_Set(Initialize); - WinUSBX_Set(QueryDeviceInformation); - WinUSBX_Set(QueryInterfaceSettings); - WinUSBX_Set(QueryPipe); - WinUSBX_Set(ReadPipe); - WinUSBX_Set(ResetPipe); - WinUSBX_Set(SetCurrentAlternateSetting); - WinUSBX_Set(SetPipePolicy); - WinUSBX_Set(SetPowerPolicy); - WinUSBX_Set(WritePipe); - if (!native_winusb) { - WinUSBX_Set(ResetDevice); - } - if (WinUSBX[i].Initialize != NULL) { - WinUSBX[i].initialized = true; - usbi_dbg("initalized sub API %s", sub_api_name[i]); - } else { - usbi_warn(ctx, "Failed to initalize sub API %s", sub_api_name[i]); - WinUSBX[i].initialized = false; - } - } - return LIBUSB_SUCCESS; -} - -static int winusbx_exit(int sub_api) -{ - return LIBUSB_SUCCESS; -} - -// NB: open and close must ensure that they only handle interface of -// the right API type, as these functions can be called wholesale from -// composite_open(), with interfaces belonging to different APIs -static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - - HANDLE file_handle; - int i; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - // WinUSB requires a seperate handle for each interface - for (i = 0; i < USB_MAXINTERFACES; i++) { - if ( (priv->usb_interface[i].path != NULL) - && (priv->usb_interface[i].apib->id == USB_API_WINUSBX) ) { - file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - if (file_handle == INVALID_HANDLE_VALUE) { - usbi_err(ctx, "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0)); - switch(GetLastError()) { - case ERROR_FILE_NOT_FOUND: // The device was disconnected - return LIBUSB_ERROR_NO_DEVICE; - case ERROR_ACCESS_DENIED: - return LIBUSB_ERROR_ACCESS; - default: - return LIBUSB_ERROR_IO; - } - } - handle_priv->interface_handle[i].dev_handle = file_handle; - } - } - - return LIBUSB_SUCCESS; -} - -static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE file_handle; - int i; - - if (sub_api == SUB_API_NOTSET) - sub_api = priv->sub_api; - if (!WinUSBX[sub_api].initialized) - return; - - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (priv->usb_interface[i].apib->id == USB_API_WINUSBX) { - file_handle = handle_priv->interface_handle[i].dev_handle; - if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) { - CloseHandle(file_handle); - } - } - } -} - -static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE winusb_handle = handle_priv->interface_handle[iface].api_handle; - UCHAR policy; - ULONG timeout = 0; - uint8_t endpoint_address; - int i; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - // With handle and enpoints set (in parent), we can setup the default pipe properties - // see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx - for (i=-1; i<priv->usb_interface[iface].nb_endpoints; i++) { - endpoint_address =(i==-1)?0:priv->usb_interface[iface].endpoint[i]; - if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, - PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout)) { - usbi_dbg("failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address); - } - if ((i == -1) || (sub_api == SUB_API_LIBUSB0)) { - continue; // Other policies don't apply to control endpoint or libusb0 - } - policy = false; - if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, - SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy)) { - usbi_dbg("failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address); - } - if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, - IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy)) { - usbi_dbg("failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address); - } - policy = true; - /* ALLOW_PARTIAL_READS must be enabled due to likely libusbK bug. See: - https://sourceforge.net/mailarchive/message.php?msg_id=29736015 */ - if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, - ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy)) { - usbi_dbg("failed to enable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address); - } - if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address, - AUTO_CLEAR_STALL, sizeof(UCHAR), &policy)) { - usbi_dbg("failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address); - } - } - - return LIBUSB_SUCCESS; -} - -static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE); - HANDLE file_handle, winusb_handle; - DWORD err; - int i; - SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; - HDEVINFO dev_info = INVALID_HANDLE_VALUE; - SP_DEVINFO_DATA dev_info_data; - char* dev_path_no_guid = NULL; - char filter_path[] = "\\\\.\\libusb0-0000"; - bool found_filter = false; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - // If the device is composite, but using the default Windows composite parent driver (usbccgp) - // or if it's the first WinUSB-like interface, we get a handle through Initialize(). - if ((is_using_usbccgp) || (iface == 0)) { - // composite device (independent interfaces) or interface 0 - file_handle = handle_priv->interface_handle[iface].dev_handle; - if ((file_handle == 0) || (file_handle == INVALID_HANDLE_VALUE)) { - return LIBUSB_ERROR_NOT_FOUND; - } - - if (!WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { - handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; - err = GetLastError(); - switch(err) { - case ERROR_BAD_COMMAND: - // The device was disconnected - usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(0)); - return LIBUSB_ERROR_NO_DEVICE; - default: - // it may be that we're using the libusb0 filter driver. - // TODO: can we move this whole business into the K/0 DLL? - for (i = 0; ; i++) { - safe_free(dev_interface_details); - safe_free(dev_path_no_guid); - dev_interface_details = get_interface_details_filter(ctx, &dev_info, &dev_info_data, &GUID_DEVINTERFACE_LIBUSB0_FILTER, i, filter_path); - if ((found_filter) || (dev_interface_details == NULL)) { - break; - } - // ignore GUID part - dev_path_no_guid = sanitize_path(strtok(dev_interface_details->DevicePath, "{")); - if (safe_strncmp(dev_path_no_guid, priv->usb_interface[iface].path, safe_strlen(dev_path_no_guid)) == 0) { - file_handle = CreateFileA(filter_path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - if (file_handle == INVALID_HANDLE_VALUE) { - usbi_err(ctx, "could not open device %s: %s", filter_path, windows_error_str(0)); - } else { - WinUSBX[sub_api].Free(winusb_handle); - if (!WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { - continue; - } - found_filter = true; - break; - } - } - } - if (!found_filter) { - usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(err)); - return LIBUSB_ERROR_ACCESS; - } - } - } - handle_priv->interface_handle[iface].api_handle = winusb_handle; - } else { - // For all other interfaces, use GetAssociatedInterface() - winusb_handle = handle_priv->interface_handle[0].api_handle; - // It is a requirement for multiple interface devices on Windows that, to you - // must first claim the first interface before you claim the others - if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) { - file_handle = handle_priv->interface_handle[0].dev_handle; - if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) { - handle_priv->interface_handle[0].api_handle = winusb_handle; - usbi_warn(ctx, "auto-claimed interface 0 (required to claim %d with WinUSB)", iface); - } else { - usbi_warn(ctx, "failed to auto-claim interface 0 (required to claim %d with WinUSB): %s", iface, windows_error_str(0)); - return LIBUSB_ERROR_ACCESS; - } - } - if (!WinUSBX[sub_api].GetAssociatedInterface(winusb_handle, (UCHAR)(iface-1), - &handle_priv->interface_handle[iface].api_handle)) { - handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; - switch(GetLastError()) { - case ERROR_NO_MORE_ITEMS: // invalid iface - return LIBUSB_ERROR_NOT_FOUND; - case ERROR_BAD_COMMAND: // The device was disconnected - return LIBUSB_ERROR_NO_DEVICE; - case ERROR_ALREADY_EXISTS: // already claimed - return LIBUSB_ERROR_BUSY; - default: - usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0)); - return LIBUSB_ERROR_ACCESS; - } - } - } - usbi_dbg("claimed interface %d", iface); - handle_priv->active_interface = iface; - - return LIBUSB_SUCCESS; -} - -static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE winusb_handle; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - winusb_handle = handle_priv->interface_handle[iface].api_handle; - if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) { - return LIBUSB_ERROR_NOT_FOUND; - } - - WinUSBX[sub_api].Free(winusb_handle); - handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; - - return LIBUSB_SUCCESS; -} - -/* - * Return the first valid interface (of the same API type), for control transfers - */ -static int get_valid_interface(struct libusb_device_handle *dev_handle, int api_id) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - int i; - - if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) { - usbi_dbg("unsupported API ID"); - return -1; - } - - for (i=0; i<USB_MAXINTERFACES; i++) { - if ( (handle_priv->interface_handle[i].dev_handle != 0) - && (handle_priv->interface_handle[i].dev_handle != INVALID_HANDLE_VALUE) - && (handle_priv->interface_handle[i].api_handle != 0) - && (handle_priv->interface_handle[i].api_handle != INVALID_HANDLE_VALUE) - && (priv->usb_interface[i].apib->id == api_id) ) { - return i; - } - } - return -1; -} - -/* - * Lookup interface by endpoint address. -1 if not found - */ -static int interface_by_endpoint(struct windows_device_priv *priv, - struct windows_device_handle_priv *handle_priv, uint8_t endpoint_address) -{ - int i, j; - for (i=0; i<USB_MAXINTERFACES; i++) { - if (handle_priv->interface_handle[i].api_handle == INVALID_HANDLE_VALUE) - continue; - if (handle_priv->interface_handle[i].api_handle == 0) - continue; - if (priv->usb_interface[i].endpoint == NULL) - continue; - for (j=0; j<priv->usb_interface[i].nb_endpoints; j++) { - if (priv->usb_interface[i].endpoint[j] == endpoint_address) { - return i; - } - } - } - return -1; -} - -static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_handle_priv *handle_priv = _device_handle_priv( - transfer->dev_handle); - WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *) transfer->buffer; - ULONG size; - HANDLE winusb_handle; - int current_interface; - struct winfd wfd; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - transfer_priv->pollable_fd = INVALID_WINFD; - size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; - - if (size > MAX_CTRL_BUFFER_LENGTH) - return LIBUSB_ERROR_INVALID_PARAM; - - current_interface = get_valid_interface(transfer->dev_handle, USB_API_WINUSBX); - if (current_interface < 0) { - if (auto_claim(transfer, ¤t_interface, USB_API_WINUSBX) != LIBUSB_SUCCESS) { - return LIBUSB_ERROR_NOT_FOUND; - } - } - - usbi_dbg("will use interface %d", current_interface); - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - wfd = usbi_create_fd(winusb_handle, RW_READ, NULL, NULL); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) { - return LIBUSB_ERROR_NO_MEM; - } - - // Sending of set configuration control requests from WinUSB creates issues - if ( ((setup->request_type & (0x03 << 5)) == LIBUSB_REQUEST_TYPE_STANDARD) - && (setup->request == LIBUSB_REQUEST_SET_CONFIGURATION) ) { - if (setup->value != priv->active_config) { - usbi_warn(ctx, "cannot set configuration other than the default one"); - usbi_free_fd(&wfd); - return LIBUSB_ERROR_INVALID_PARAM; - } - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = 0; - } else { - if (!WinUSBX[sub_api].ControlTransfer(wfd.handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, wfd.overlapped)) { - if(GetLastError() != ERROR_IO_PENDING) { - usbi_warn(ctx, "ControlTransfer failed: %s", windows_error_str(0)); - usbi_free_fd(&wfd); - return LIBUSB_ERROR_IO; - } - } else { - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = (DWORD)size; - } - } - - // Use priv_transfer to store data needed for async polling - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - - return LIBUSB_SUCCESS; -} - -static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE winusb_handle; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - if (altsetting > 255) { - return LIBUSB_ERROR_INVALID_PARAM; - } - - winusb_handle = handle_priv->interface_handle[iface].api_handle; - if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) { - usbi_err(ctx, "interface must be claimed first"); - return LIBUSB_ERROR_NOT_FOUND; - } - - if (!WinUSBX[sub_api].SetCurrentAlternateSetting(winusb_handle, (UCHAR)altsetting)) { - usbi_err(ctx, "SetCurrentAlternateSetting failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_IO; - } - - return LIBUSB_SUCCESS; -} - -static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - HANDLE winusb_handle; - bool ret; - int current_interface; - struct winfd wfd; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - transfer_priv->pollable_fd = INVALID_WINFD; - - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); - - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - wfd = usbi_create_fd(winusb_handle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) { - return LIBUSB_ERROR_NO_MEM; - } - - if (IS_XFERIN(transfer)) { - usbi_dbg("reading %d bytes", transfer->length); - ret = WinUSBX[sub_api].ReadPipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); - } else { - usbi_dbg("writing %d bytes", transfer->length); - ret = WinUSBX[sub_api].WritePipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); - } - if (!ret) { - if(GetLastError() != ERROR_IO_PENDING) { - usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0)); - usbi_free_fd(&wfd); - return LIBUSB_ERROR_IO; - } - } else { - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = (DWORD)transfer->length; - } - - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - - return LIBUSB_SUCCESS; -} - -static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE winusb_handle; - int current_interface; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - current_interface = interface_by_endpoint(priv, handle_priv, endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface); - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - if (!WinUSBX[sub_api].ResetPipe(winusb_handle, endpoint)) { - usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_DEVICE; - } - - return LIBUSB_SUCCESS; -} - -/* - * from http://www.winvistatips.com/winusb-bugchecks-t335323.html (confirmed - * through testing as well): - * "You can not call WinUsb_AbortPipe on control pipe. You can possibly cancel - * the control transfer using CancelIo" - */ -static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer) -{ - // Cancelling of the I/O is done in the parent - return LIBUSB_SUCCESS; -} - -static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - HANDLE winusb_handle; - int current_interface; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - current_interface = transfer_priv->interface_number; - if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { - usbi_err(ctx, "program assertion failed: invalid interface_number"); - return LIBUSB_ERROR_NOT_FOUND; - } - usbi_dbg("will use interface %d", current_interface); - - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - if (!WinUSBX[sub_api].AbortPipe(winusb_handle, transfer->endpoint)) { - usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_DEVICE; - } - - return LIBUSB_SUCCESS; -} - -/* - * from the "How to Use WinUSB to Communicate with a USB Device" Microsoft white paper - * (http://www.microsoft.com/whdc/connect/usb/winusb_howto.mspx): - * "WinUSB does not support host-initiated reset port and cycle port operations" and - * IOCTL_INTERNAL_USB_CYCLE_PORT is only available in kernel mode and the - * IOCTL_USB_HUB_CYCLE_PORT ioctl was removed from Vista => the best we can do is - * cycle the pipes (and even then, the control pipe can not be reset using WinUSB) - */ -// TODO: (post hotplug): see if we can force eject the device and redetect it (reuse hotplug?) -static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct winfd wfd; - HANDLE winusb_handle; - int i, j; - - CHECK_WINUSBX_AVAILABLE(sub_api); - - // Reset any available pipe (except control) - for (i=0; i<USB_MAXINTERFACES; i++) { - winusb_handle = handle_priv->interface_handle[i].api_handle; - for (wfd = handle_to_winfd(winusb_handle); wfd.fd > 0;) - { - // Cancel any pollable I/O - usbi_remove_pollfd(ctx, wfd.fd); - usbi_free_fd(&wfd); - wfd = handle_to_winfd(winusb_handle); - } - - if ( (winusb_handle != 0) && (winusb_handle != INVALID_HANDLE_VALUE)) { - for (j=0; j<priv->usb_interface[i].nb_endpoints; j++) { - usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]); - if (!WinUSBX[sub_api].AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) { - usbi_err(ctx, "AbortPipe (pipe address %02X) failed: %s", - priv->usb_interface[i].endpoint[j], windows_error_str(0)); - } - // FlushPipe seems to fail on OUT pipes - if (IS_EPIN(priv->usb_interface[i].endpoint[j]) - && (!WinUSBX[sub_api].FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) ) { - usbi_err(ctx, "FlushPipe (pipe address %02X) failed: %s", - priv->usb_interface[i].endpoint[j], windows_error_str(0)); - } - if (!WinUSBX[sub_api].ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) { - usbi_err(ctx, "ResetPipe (pipe address %02X) failed: %s", - priv->usb_interface[i].endpoint[j], windows_error_str(0)); - } - } - } - } - - // libusbK & libusb0 have the ability to issue an actual device reset - if (WinUSBX[sub_api].ResetDevice != NULL) { - winusb_handle = handle_priv->interface_handle[0].api_handle; - if ( (winusb_handle != 0) && (winusb_handle != INVALID_HANDLE_VALUE)) { - WinUSBX[sub_api].ResetDevice(winusb_handle); - } - } - return LIBUSB_SUCCESS; -} - -static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) -{ - itransfer->transferred += io_size; - return LIBUSB_TRANSFER_COMPLETED; -} - -/* - * Internal HID Support functions (from libusb-win32) - * Note that functions that complete data transfer synchronously must return - * LIBUSB_COMPLETED instead of LIBUSB_SUCCESS - */ -static int _hid_get_hid_descriptor(struct hid_device_priv* dev, void *data, size_t *size); -static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, size_t *size); - -static int _hid_wcslen(WCHAR *str) -{ - int i = 0; - while (str[i] && (str[i] != 0x409)) { - i++; - } - return i; -} - -static int _hid_get_device_descriptor(struct hid_device_priv* dev, void *data, size_t *size) -{ - struct libusb_device_descriptor d; - - d.bLength = LIBUSB_DT_DEVICE_SIZE; - d.bDescriptorType = LIBUSB_DT_DEVICE; - d.bcdUSB = 0x0200; /* 2.00 */ - d.bDeviceClass = 0; - d.bDeviceSubClass = 0; - d.bDeviceProtocol = 0; - d.bMaxPacketSize0 = 64; /* fix this! */ - d.idVendor = (uint16_t)dev->vid; - d.idProduct = (uint16_t)dev->pid; - d.bcdDevice = 0x0100; - d.iManufacturer = dev->string_index[0]; - d.iProduct = dev->string_index[1]; - d.iSerialNumber = dev->string_index[2]; - d.bNumConfigurations = 1; - - if (*size > LIBUSB_DT_DEVICE_SIZE) - *size = LIBUSB_DT_DEVICE_SIZE; - memcpy(data, &d, *size); - return LIBUSB_COMPLETED; -} - -static int _hid_get_config_descriptor(struct hid_device_priv* dev, void *data, size_t *size) -{ - char num_endpoints = 0; - size_t config_total_len = 0; - char tmp[HID_MAX_CONFIG_DESC_SIZE]; - struct libusb_config_descriptor *cd; - struct libusb_interface_descriptor *id; - struct libusb_hid_descriptor *hd; - struct libusb_endpoint_descriptor *ed; - size_t tmp_size; - - if (dev->input_report_size) - num_endpoints++; - if (dev->output_report_size) - num_endpoints++; - - config_total_len = LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE - + LIBUSB_DT_HID_SIZE + num_endpoints * LIBUSB_DT_ENDPOINT_SIZE; - - - cd = (struct libusb_config_descriptor *)tmp; - id = (struct libusb_interface_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE); - hd = (struct libusb_hid_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE - + LIBUSB_DT_INTERFACE_SIZE); - ed = (struct libusb_endpoint_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE - + LIBUSB_DT_INTERFACE_SIZE - + LIBUSB_DT_HID_SIZE); - - cd->bLength = LIBUSB_DT_CONFIG_SIZE; - cd->bDescriptorType = LIBUSB_DT_CONFIG; - cd->wTotalLength = (uint16_t) config_total_len; - cd->bNumInterfaces = 1; - cd->bConfigurationValue = 1; - cd->iConfiguration = 0; - cd->bmAttributes = 1 << 7; /* bus powered */ - cd->MaxPower = 50; - - id->bLength = LIBUSB_DT_INTERFACE_SIZE; - id->bDescriptorType = LIBUSB_DT_INTERFACE; - id->bInterfaceNumber = 0; - id->bAlternateSetting = 0; - id->bNumEndpoints = num_endpoints; - id->bInterfaceClass = 3; - id->bInterfaceSubClass = 0; - id->bInterfaceProtocol = 0; - id->iInterface = 0; - - tmp_size = LIBUSB_DT_HID_SIZE; - _hid_get_hid_descriptor(dev, hd, &tmp_size); - - if (dev->input_report_size) { - ed->bLength = LIBUSB_DT_ENDPOINT_SIZE; - ed->bDescriptorType = LIBUSB_DT_ENDPOINT; - ed->bEndpointAddress = HID_IN_EP; - ed->bmAttributes = 3; - ed->wMaxPacketSize = dev->input_report_size - 1; - ed->bInterval = 10; - ed = (struct libusb_endpoint_descriptor *)((char*)ed + LIBUSB_DT_ENDPOINT_SIZE); - } - - if (dev->output_report_size) { - ed->bLength = LIBUSB_DT_ENDPOINT_SIZE; - ed->bDescriptorType = LIBUSB_DT_ENDPOINT; - ed->bEndpointAddress = HID_OUT_EP; - ed->bmAttributes = 3; - ed->wMaxPacketSize = dev->output_report_size - 1; - ed->bInterval = 10; - } - - if (*size > config_total_len) - *size = config_total_len; - memcpy(data, tmp, *size); - return LIBUSB_COMPLETED; -} - -static int _hid_get_string_descriptor(struct hid_device_priv* dev, int _index, - void *data, size_t *size) -{ - void *tmp = NULL; - size_t tmp_size = 0; - int i; - - /* language ID, EN-US */ - char string_langid[] = { - 0x09, - 0x04 - }; - - if ((*size < 2) || (*size > 255)) { - return LIBUSB_ERROR_OVERFLOW; - } - - if (_index == 0) { - tmp = string_langid; - tmp_size = sizeof(string_langid)+2; - } else { - for (i=0; i<3; i++) { - if (_index == (dev->string_index[i])) { - tmp = dev->string[i]; - tmp_size = (_hid_wcslen(dev->string[i])+1) * sizeof(WCHAR); - break; - } - } - if (i == 3) { // not found - return LIBUSB_ERROR_INVALID_PARAM; - } - } - - if(!tmp_size) { - return LIBUSB_ERROR_INVALID_PARAM; - } - - if (tmp_size < *size) { - *size = tmp_size; - } - // 2 byte header - ((uint8_t*)data)[0] = (uint8_t)*size; - ((uint8_t*)data)[1] = LIBUSB_DT_STRING; - memcpy((uint8_t*)data+2, tmp, *size-2); - return LIBUSB_COMPLETED; -} - -static int _hid_get_hid_descriptor(struct hid_device_priv* dev, void *data, size_t *size) -{ - struct libusb_hid_descriptor d; - uint8_t tmp[MAX_HID_DESCRIPTOR_SIZE]; - size_t report_len = MAX_HID_DESCRIPTOR_SIZE; - - _hid_get_report_descriptor(dev, tmp, &report_len); - - d.bLength = LIBUSB_DT_HID_SIZE; - d.bDescriptorType = LIBUSB_DT_HID; - d.bcdHID = 0x0110; /* 1.10 */ - d.bCountryCode = 0; - d.bNumDescriptors = 1; - d.bClassDescriptorType = LIBUSB_DT_REPORT; - d.wClassDescriptorLength = (uint16_t)report_len; - - if (*size > LIBUSB_DT_HID_SIZE) - *size = LIBUSB_DT_HID_SIZE; - memcpy(data, &d, *size); - return LIBUSB_COMPLETED; -} - -static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, size_t *size) -{ - uint8_t d[MAX_HID_DESCRIPTOR_SIZE]; - size_t i = 0; - - /* usage page (0xFFA0 == vendor defined) */ - d[i++] = 0x06; d[i++] = 0xA0; d[i++] = 0xFF; - /* usage (vendor defined) */ - d[i++] = 0x09; d[i++] = 0x01; - /* start collection (application) */ - d[i++] = 0xA1; d[i++] = 0x01; - /* input report */ - if (dev->input_report_size) { - /* usage (vendor defined) */ - d[i++] = 0x09; d[i++] = 0x01; - /* logical minimum (0) */ - d[i++] = 0x15; d[i++] = 0x00; - /* logical maximum (255) */ - d[i++] = 0x25; d[i++] = 0xFF; - /* report size (8 bits) */ - d[i++] = 0x75; d[i++] = 0x08; - /* report count */ - d[i++] = 0x95; d[i++] = (uint8_t)dev->input_report_size - 1; - /* input (data, variable, absolute) */ - d[i++] = 0x81; d[i++] = 0x00; - } - /* output report */ - if (dev->output_report_size) { - /* usage (vendor defined) */ - d[i++] = 0x09; d[i++] = 0x02; - /* logical minimum (0) */ - d[i++] = 0x15; d[i++] = 0x00; - /* logical maximum (255) */ - d[i++] = 0x25; d[i++] = 0xFF; - /* report size (8 bits) */ - d[i++] = 0x75; d[i++] = 0x08; - /* report count */ - d[i++] = 0x95; d[i++] = (uint8_t)dev->output_report_size - 1; - /* output (data, variable, absolute) */ - d[i++] = 0x91; d[i++] = 0x00; - } - /* feature report */ - if (dev->feature_report_size) { - /* usage (vendor defined) */ - d[i++] = 0x09; d[i++] = 0x03; - /* logical minimum (0) */ - d[i++] = 0x15; d[i++] = 0x00; - /* logical maximum (255) */ - d[i++] = 0x25; d[i++] = 0xFF; - /* report size (8 bits) */ - d[i++] = 0x75; d[i++] = 0x08; - /* report count */ - d[i++] = 0x95; d[i++] = (uint8_t)dev->feature_report_size - 1; - /* feature (data, variable, absolute) */ - d[i++] = 0xb2; d[i++] = 0x02; d[i++] = 0x01; - } - - /* end collection */ - d[i++] = 0xC0; - - if (*size > i) - *size = i; - memcpy(data, d, *size); - return LIBUSB_COMPLETED; -} - -static int _hid_get_descriptor(struct hid_device_priv* dev, HANDLE hid_handle, int recipient, - int type, int _index, void *data, size_t *size) -{ - switch(type) { - case LIBUSB_DT_DEVICE: - usbi_dbg("LIBUSB_DT_DEVICE"); - return _hid_get_device_descriptor(dev, data, size); - case LIBUSB_DT_CONFIG: - usbi_dbg("LIBUSB_DT_CONFIG"); - if (!_index) - return _hid_get_config_descriptor(dev, data, size); - return LIBUSB_ERROR_INVALID_PARAM; - case LIBUSB_DT_STRING: - usbi_dbg("LIBUSB_DT_STRING"); - return _hid_get_string_descriptor(dev, _index, data, size); - case LIBUSB_DT_HID: - usbi_dbg("LIBUSB_DT_HID"); - if (!_index) - return _hid_get_hid_descriptor(dev, data, size); - return LIBUSB_ERROR_INVALID_PARAM; - case LIBUSB_DT_REPORT: - usbi_dbg("LIBUSB_DT_REPORT"); - if (!_index) - return _hid_get_report_descriptor(dev, data, size); - return LIBUSB_ERROR_INVALID_PARAM; - case LIBUSB_DT_PHYSICAL: - usbi_dbg("LIBUSB_DT_PHYSICAL"); - if (HidD_GetPhysicalDescriptor(hid_handle, data, (ULONG)*size)) - return LIBUSB_COMPLETED; - return LIBUSB_ERROR_OTHER; - } - usbi_dbg("unsupported"); - return LIBUSB_ERROR_INVALID_PARAM; -} - -static int _hid_get_report(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data, - struct windows_transfer_priv *tp, size_t *size, OVERLAPPED* overlapped, - int report_type) -{ - uint8_t *buf; - DWORD ioctl_code, read_size, expected_size = (DWORD)*size; - int r = LIBUSB_SUCCESS; - - if (tp->hid_buffer != NULL) { - usbi_dbg("program assertion failed: hid_buffer is not NULL"); - } - - if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) { - usbi_dbg("invalid size (%d)", *size); - return LIBUSB_ERROR_INVALID_PARAM; - } - - switch (report_type) { - case HID_REPORT_TYPE_INPUT: - ioctl_code = IOCTL_HID_GET_INPUT_REPORT; - break; - case HID_REPORT_TYPE_FEATURE: - ioctl_code = IOCTL_HID_GET_FEATURE; - break; - default: - usbi_dbg("unknown HID report type %d", report_type); - return LIBUSB_ERROR_INVALID_PARAM; - } - - // Add a trailing byte to detect overflows - buf = (uint8_t*)calloc(expected_size+1, 1); - if (buf == NULL) { - return LIBUSB_ERROR_NO_MEM; - } - buf[0] = (uint8_t)id; // Must be set always - usbi_dbg("report ID: 0x%02X", buf[0]); - - tp->hid_expected_size = expected_size; - read_size = expected_size; - - // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0) - if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size+1, - buf, expected_size+1, &read_size, overlapped)) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_dbg("Failed to Read HID Report: %s", windows_error_str(0)); - safe_free(buf); - return LIBUSB_ERROR_IO; - } - // Asynchronous wait - tp->hid_buffer = buf; - tp->hid_dest = (uint8_t*)data; // copy dest, as not necessarily the start of the transfer buffer - return LIBUSB_SUCCESS; - } - - // Transfer completed synchronously => copy and discard extra buffer - if (read_size == 0) { - usbi_warn(NULL, "program assertion failed - read completed synchronously, but no data was read"); - *size = 0; - } else { - if (buf[0] != id) { - usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id); - } - if ((size_t)read_size > expected_size) { - r = LIBUSB_ERROR_OVERFLOW; - usbi_dbg("OVERFLOW!"); - } else { - r = LIBUSB_COMPLETED; - } - - *size = MIN((size_t)read_size, *size); - if (id == 0) { - // Discard report ID - memcpy(data, buf+1, *size); - } else { - memcpy(data, buf, *size); - } - } - safe_free(buf); - return r; -} - -static int _hid_set_report(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data, - struct windows_transfer_priv *tp, size_t *size, OVERLAPPED* overlapped, - int report_type) -{ - uint8_t *buf = NULL; - DWORD ioctl_code, write_size= (DWORD)*size; - - if (tp->hid_buffer != NULL) { - usbi_dbg("program assertion failed: hid_buffer is not NULL"); - } - - if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) { - usbi_dbg("invalid size (%d)", *size); - return LIBUSB_ERROR_INVALID_PARAM; - } - - switch (report_type) { - case HID_REPORT_TYPE_OUTPUT: - ioctl_code = IOCTL_HID_SET_OUTPUT_REPORT; - break; - case HID_REPORT_TYPE_FEATURE: - ioctl_code = IOCTL_HID_SET_FEATURE; - break; - default: - usbi_dbg("unknown HID report type %d", report_type); - return LIBUSB_ERROR_INVALID_PARAM; - } - - usbi_dbg("report ID: 0x%02X", id); - // When report IDs are not used (i.e. when id == 0), we must add - // a null report ID. Otherwise, we just use original data buffer - if (id == 0) { - write_size++; - } - buf = (uint8_t*) malloc(write_size); - if (buf == NULL) { - return LIBUSB_ERROR_NO_MEM; - } - if (id == 0) { - buf[0] = 0; - memcpy(buf + 1, data, *size); - } else { - // This seems like a waste, but if we don't duplicate the - // data, we'll get issues when freeing hid_buffer - memcpy(buf, data, *size); - if (buf[0] != id) { - usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id); - } - } - - // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0) - if (!DeviceIoControl(hid_handle, ioctl_code, buf, write_size, - buf, write_size, &write_size, overlapped)) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_dbg("Failed to Write HID Output Report: %s", windows_error_str(0)); - safe_free(buf); - return LIBUSB_ERROR_IO; - } - tp->hid_buffer = buf; - tp->hid_dest = NULL; - return LIBUSB_SUCCESS; - } - - // Transfer completed synchronously - *size = write_size; - if (write_size == 0) { - usbi_dbg("program assertion failed - write completed synchronously, but no data was written"); - } - safe_free(buf); - return LIBUSB_COMPLETED; -} - -static int _hid_class_request(struct hid_device_priv* dev, HANDLE hid_handle, int request_type, - int request, int value, int _index, void *data, struct windows_transfer_priv *tp, - size_t *size, OVERLAPPED* overlapped) -{ - int report_type = (value >> 8) & 0xFF; - int report_id = value & 0xFF; - - if ( (LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_INTERFACE) - && (LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_DEVICE) ) - return LIBUSB_ERROR_INVALID_PARAM; - - if (LIBUSB_REQ_OUT(request_type) && request == HID_REQ_SET_REPORT) - return _hid_set_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type); - - if (LIBUSB_REQ_IN(request_type) && request == HID_REQ_GET_REPORT) - return _hid_get_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type); - - return LIBUSB_ERROR_INVALID_PARAM; -} - - -/* - * HID API functions - */ -static int hid_init(int sub_api, struct libusb_context *ctx) -{ - DLL_LOAD(hid.dll, HidD_GetAttributes, TRUE); - DLL_LOAD(hid.dll, HidD_GetHidGuid, TRUE); - DLL_LOAD(hid.dll, HidD_GetPreparsedData, TRUE); - DLL_LOAD(hid.dll, HidD_FreePreparsedData, TRUE); - DLL_LOAD(hid.dll, HidD_GetManufacturerString, TRUE); - DLL_LOAD(hid.dll, HidD_GetProductString, TRUE); - DLL_LOAD(hid.dll, HidD_GetSerialNumberString, TRUE); - DLL_LOAD(hid.dll, HidP_GetCaps, TRUE); - DLL_LOAD(hid.dll, HidD_SetNumInputBuffers, TRUE); - DLL_LOAD(hid.dll, HidD_SetFeature, TRUE); - DLL_LOAD(hid.dll, HidD_GetFeature, TRUE); - DLL_LOAD(hid.dll, HidD_GetPhysicalDescriptor, TRUE); - DLL_LOAD(hid.dll, HidD_GetInputReport, FALSE); - DLL_LOAD(hid.dll, HidD_SetOutputReport, FALSE); - DLL_LOAD(hid.dll, HidD_FlushQueue, TRUE); - DLL_LOAD(hid.dll, HidP_GetValueCaps, TRUE); - - api_hid_available = true; - return LIBUSB_SUCCESS; -} - -static int hid_exit(int sub_api) -{ - return LIBUSB_SUCCESS; -} - -// NB: open and close must ensure that they only handle interface of -// the right API type, as these functions can be called wholesale from -// composite_open(), with interfaces belonging to different APIs -static int hid_open(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - - HIDD_ATTRIBUTES hid_attributes; - PHIDP_PREPARSED_DATA preparsed_data = NULL; - HIDP_CAPS capabilities; - HIDP_VALUE_CAPS *value_caps; - - HANDLE hid_handle = INVALID_HANDLE_VALUE; - int i, j; - // report IDs handling - ULONG size[3]; - const char* type[3] = {"input", "output", "feature"}; - int nb_ids[2]; // zero and nonzero report IDs - - CHECK_HID_AVAILABLE; - if (priv->hid == NULL) { - usbi_err(ctx, "program assertion failed - private HID structure is unitialized"); - return LIBUSB_ERROR_NOT_FOUND; - } - - for (i = 0; i < USB_MAXINTERFACES; i++) { - if ( (priv->usb_interface[i].path != NULL) - && (priv->usb_interface[i].apib->id == USB_API_HID) ) { - hid_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - /* - * http://www.lvr.com/hidfaq.htm: Why do I receive "Access denied" when attempting to access my HID? - * "Windows 2000 and later have exclusive read/write access to HIDs that are configured as a system - * keyboards or mice. An application can obtain a handle to a system keyboard or mouse by not - * requesting READ or WRITE access with CreateFile. Applications can then use HidD_SetFeature and - * HidD_GetFeature (if the device supports Feature reports)." - */ - if (hid_handle == INVALID_HANDLE_VALUE) { - usbi_warn(ctx, "could not open HID device in R/W mode (keyboard or mouse?) - trying without"); - hid_handle = CreateFileA(priv->usb_interface[i].path, 0, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - if (hid_handle == INVALID_HANDLE_VALUE) { - usbi_err(ctx, "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0)); - switch(GetLastError()) { - case ERROR_FILE_NOT_FOUND: // The device was disconnected - return LIBUSB_ERROR_NO_DEVICE; - case ERROR_ACCESS_DENIED: - return LIBUSB_ERROR_ACCESS; - default: - return LIBUSB_ERROR_IO; - } - } - priv->usb_interface[i].restricted_functionality = true; - } - handle_priv->interface_handle[i].api_handle = hid_handle; - } - } - - hid_attributes.Size = sizeof(hid_attributes); - do { - if (!HidD_GetAttributes(hid_handle, &hid_attributes)) { - usbi_err(ctx, "could not gain access to HID top collection (HidD_GetAttributes)"); - break; - } - - priv->hid->vid = hid_attributes.VendorID; - priv->hid->pid = hid_attributes.ProductID; - - // Set the maximum available input buffer size - for (i=32; HidD_SetNumInputBuffers(hid_handle, i); i*=2); - usbi_dbg("set maximum input buffer size to %d", i/2); - - // Get the maximum input and output report size - if (!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) { - usbi_err(ctx, "could not read HID preparsed data (HidD_GetPreparsedData)"); - break; - } - if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) { - usbi_err(ctx, "could not parse HID capabilities (HidP_GetCaps)"); - break; - } - - // Find out if interrupt will need report IDs - size[0] = capabilities.NumberInputValueCaps; - size[1] = capabilities.NumberOutputValueCaps; - size[2] = capabilities.NumberFeatureValueCaps; - for (j=HidP_Input; j<=HidP_Feature; j++) { - usbi_dbg("%d HID %s report value(s) found", size[j], type[j]); - priv->hid->uses_report_ids[j] = false; - if (size[j] > 0) { - value_caps = (HIDP_VALUE_CAPS*) calloc(size[j], sizeof(HIDP_VALUE_CAPS)); - if ( (value_caps != NULL) - && (HidP_GetValueCaps((HIDP_REPORT_TYPE)j, value_caps, &size[j], preparsed_data) == HIDP_STATUS_SUCCESS) - && (size[j] >= 1) ) { - nb_ids[0] = 0; - nb_ids[1] = 0; - for (i=0; i<(int)size[j]; i++) { - usbi_dbg(" Report ID: 0x%02X", value_caps[i].ReportID); - if (value_caps[i].ReportID != 0) { - nb_ids[1]++; - } else { - nb_ids[0]++; - } - } - if (nb_ids[1] != 0) { - if (nb_ids[0] != 0) { - usbi_warn(ctx, "program assertion failed: zero and nonzero report IDs used for %s", - type[j]); - } - priv->hid->uses_report_ids[j] = true; - } - } else { - usbi_warn(ctx, " could not process %s report IDs", type[j]); - } - safe_free(value_caps); - } - } - - // Set the report sizes - priv->hid->input_report_size = capabilities.InputReportByteLength; - priv->hid->output_report_size = capabilities.OutputReportByteLength; - priv->hid->feature_report_size = capabilities.FeatureReportByteLength; - - // Fetch string descriptors - priv->hid->string_index[0] = priv->dev_descriptor.iManufacturer; - if (priv->hid->string_index[0] != 0) { - HidD_GetManufacturerString(hid_handle, priv->hid->string[0], - sizeof(priv->hid->string[0])); - } else { - priv->hid->string[0][0] = 0; - } - priv->hid->string_index[1] = priv->dev_descriptor.iProduct; - if (priv->hid->string_index[1] != 0) { - HidD_GetProductString(hid_handle, priv->hid->string[1], - sizeof(priv->hid->string[1])); - } else { - priv->hid->string[1][0] = 0; - } - priv->hid->string_index[2] = priv->dev_descriptor.iSerialNumber; - if (priv->hid->string_index[2] != 0) { - HidD_GetSerialNumberString(hid_handle, priv->hid->string[2], - sizeof(priv->hid->string[2])); - } else { - priv->hid->string[2][0] = 0; - } - } while(0); - - if (preparsed_data) { - HidD_FreePreparsedData(preparsed_data); - } - - return LIBUSB_SUCCESS; -} - -static void hid_close(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - HANDLE file_handle; - int i; - - if (!api_hid_available) - return; - - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (priv->usb_interface[i].apib->id == USB_API_HID) { - file_handle = handle_priv->interface_handle[i].api_handle; - if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) { - CloseHandle(file_handle); - } - } - } -} - -static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - CHECK_HID_AVAILABLE; - - // NB: Disconnection detection is not possible in this function - if (priv->usb_interface[iface].path == NULL) { - return LIBUSB_ERROR_NOT_FOUND; // invalid iface - } - - // We use dev_handle as a flag for interface claimed - if (handle_priv->interface_handle[iface].dev_handle == INTERFACE_CLAIMED) { - return LIBUSB_ERROR_BUSY; // already claimed - } - - handle_priv->interface_handle[iface].dev_handle = INTERFACE_CLAIMED; - - usbi_dbg("claimed interface %d", iface); - handle_priv->active_interface = iface; - - return LIBUSB_SUCCESS; -} - -static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - CHECK_HID_AVAILABLE; - - if (priv->usb_interface[iface].path == NULL) { - return LIBUSB_ERROR_NOT_FOUND; // invalid iface - } - - if (handle_priv->interface_handle[iface].dev_handle != INTERFACE_CLAIMED) { - return LIBUSB_ERROR_NOT_FOUND; // invalid iface - } - - handle_priv->interface_handle[iface].dev_handle = INVALID_HANDLE_VALUE; - - return LIBUSB_SUCCESS; -} - -static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - - CHECK_HID_AVAILABLE; - - if (altsetting > 255) { - return LIBUSB_ERROR_INVALID_PARAM; - } - - if (altsetting != 0) { - usbi_err(ctx, "set interface altsetting not supported for altsetting >0"); - return LIBUSB_ERROR_NOT_SUPPORTED; - } - - return LIBUSB_SUCCESS; -} - -static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *) transfer->buffer; - HANDLE hid_handle; - struct winfd wfd; - int current_interface, config; - size_t size; - int r = LIBUSB_ERROR_INVALID_PARAM; - - CHECK_HID_AVAILABLE; - - transfer_priv->pollable_fd = INVALID_WINFD; - safe_free(transfer_priv->hid_buffer); - transfer_priv->hid_dest = NULL; - size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; - - if (size > MAX_CTRL_BUFFER_LENGTH) { - return LIBUSB_ERROR_INVALID_PARAM; - } - - current_interface = get_valid_interface(transfer->dev_handle, USB_API_HID); - if (current_interface < 0) { - if (auto_claim(transfer, ¤t_interface, USB_API_HID) != LIBUSB_SUCCESS) { - return LIBUSB_ERROR_NOT_FOUND; - } - } - - usbi_dbg("will use interface %d", current_interface); - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - // Always use the handle returned from usbi_create_fd (wfd.handle) - wfd = usbi_create_fd(hid_handle, RW_READ, NULL, NULL); - if (wfd.fd < 0) { - return LIBUSB_ERROR_NOT_FOUND; - } - - switch(LIBUSB_REQ_TYPE(setup->request_type)) { - case LIBUSB_REQUEST_TYPE_STANDARD: - switch(setup->request) { - case LIBUSB_REQUEST_GET_DESCRIPTOR: - r = _hid_get_descriptor(priv->hid, wfd.handle, LIBUSB_REQ_RECIPIENT(setup->request_type), - (setup->value >> 8) & 0xFF, setup->value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size); - break; - case LIBUSB_REQUEST_GET_CONFIGURATION: - r = windows_get_configuration(transfer->dev_handle, &config); - if (r == LIBUSB_SUCCESS) { - size = 1; - ((uint8_t*)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = (uint8_t)config; - r = LIBUSB_COMPLETED; - } - break; - case LIBUSB_REQUEST_SET_CONFIGURATION: - if (setup->value == priv->active_config) { - r = LIBUSB_COMPLETED; - } else { - usbi_warn(ctx, "cannot set configuration other than the default one"); - r = LIBUSB_ERROR_INVALID_PARAM; - } - break; - case LIBUSB_REQUEST_GET_INTERFACE: - size = 1; - ((uint8_t*)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = 0; - r = LIBUSB_COMPLETED; - break; - case LIBUSB_REQUEST_SET_INTERFACE: - r = hid_set_interface_altsetting(0, transfer->dev_handle, setup->index, setup->value); - if (r == LIBUSB_SUCCESS) { - r = LIBUSB_COMPLETED; - } - break; - default: - usbi_warn(ctx, "unsupported HID control request"); - r = LIBUSB_ERROR_INVALID_PARAM; - break; - } - break; - case LIBUSB_REQUEST_TYPE_CLASS: - r =_hid_class_request(priv->hid, wfd.handle, setup->request_type, setup->request, setup->value, - setup->index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv, - &size, wfd.overlapped); - break; - default: - usbi_warn(ctx, "unsupported HID control request"); - r = LIBUSB_ERROR_INVALID_PARAM; - break; - } - - if (r == LIBUSB_COMPLETED) { - // Force request to be completed synchronously. Transferred size has been set by previous call - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - // http://msdn.microsoft.com/en-us/library/ms684342%28VS.85%29.aspx - // set InternalHigh to the number of bytes transferred - wfd.overlapped->InternalHigh = (DWORD)size; - r = LIBUSB_SUCCESS; - } - - if (r == LIBUSB_SUCCESS) { - // Use priv_transfer to store data needed for async polling - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - } else { - usbi_free_fd(&wfd); - } - - return r; -} - -static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - struct winfd wfd; - HANDLE hid_handle; - bool direction_in, ret; - int current_interface, length; - DWORD size; - int r = LIBUSB_SUCCESS; - - CHECK_HID_AVAILABLE; - - transfer_priv->pollable_fd = INVALID_WINFD; - transfer_priv->hid_dest = NULL; - safe_free(transfer_priv->hid_buffer); - - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); - - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; - - wfd = usbi_create_fd(hid_handle, direction_in?RW_READ:RW_WRITE, NULL, NULL); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) { - return LIBUSB_ERROR_NO_MEM; - } - - // If report IDs are not in use, an extra prefix byte must be added - if ( ((direction_in) && (!priv->hid->uses_report_ids[0])) - || ((!direction_in) && (!priv->hid->uses_report_ids[1])) ) { - length = transfer->length+1; - } else { - length = transfer->length; - } - // Add a trailing byte to detect overflows on input - transfer_priv->hid_buffer = (uint8_t*)calloc(length+1, 1); - if (transfer_priv->hid_buffer == NULL) { - return LIBUSB_ERROR_NO_MEM; - } - transfer_priv->hid_expected_size = length; - - if (direction_in) { - transfer_priv->hid_dest = transfer->buffer; - usbi_dbg("reading %d bytes (report ID: 0x00)", length); - ret = ReadFile(wfd.handle, transfer_priv->hid_buffer, length+1, &size, wfd.overlapped); - } else { - if (!priv->hid->uses_report_ids[1]) { - memcpy(transfer_priv->hid_buffer+1, transfer->buffer, transfer->length); - } else { - // We could actually do without the calloc and memcpy in this case - memcpy(transfer_priv->hid_buffer, transfer->buffer, transfer->length); - } - usbi_dbg("writing %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]); - ret = WriteFile(wfd.handle, transfer_priv->hid_buffer, length, &size, wfd.overlapped); - } - if (!ret) { - if (GetLastError() != ERROR_IO_PENDING) { - usbi_err(ctx, "HID transfer failed: %s", windows_error_str(0)); - usbi_free_fd(&wfd); - safe_free(transfer_priv->hid_buffer); - return LIBUSB_ERROR_IO; - } - } else { - // Only write operations that completed synchronously need to free up - // hid_buffer. For reads, copy_transfer_data() handles that process. - if (!direction_in) { - safe_free(transfer_priv->hid_buffer); - } - if (size == 0) { - usbi_err(ctx, "program assertion failed - no data was transferred"); - size = 1; - } - if (size > (size_t)length) { - usbi_err(ctx, "OVERFLOW!"); - r = LIBUSB_ERROR_OVERFLOW; - } - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = size; - } - - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - - return r; -} - -static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - HANDLE hid_handle; - int current_interface; - - CHECK_HID_AVAILABLE; - - current_interface = transfer_priv->interface_number; - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - CancelIo(hid_handle); - - return LIBUSB_SUCCESS; -} - -static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - HANDLE hid_handle; - int current_interface; - - CHECK_HID_AVAILABLE; - - // Flushing the queues on all interfaces is the best we can achieve - for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) { - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - if ((hid_handle != 0) && (hid_handle != INVALID_HANDLE_VALUE)) { - HidD_FlushQueue(hid_handle); - } - } - return LIBUSB_SUCCESS; -} - -static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE hid_handle; - int current_interface; - - CHECK_HID_AVAILABLE; - - current_interface = interface_by_endpoint(priv, handle_priv, endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface); - hid_handle = handle_priv->interface_handle[current_interface].api_handle; - - // No endpoint selection with Microsoft's implementation, so we try to flush the - // whole interface. Should be OK for most case scenarios - if (!HidD_FlushQueue(hid_handle)) { - usbi_err(ctx, "Flushing of HID queue failed: %s", windows_error_str(0)); - // Device was probably disconnected - return LIBUSB_ERROR_NO_DEVICE; - } - - return LIBUSB_SUCCESS; -} - -// This extra function is only needed for HID -static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - int r = LIBUSB_TRANSFER_COMPLETED; - uint32_t corrected_size = io_size; - - if (transfer_priv->hid_buffer != NULL) { - // If we have a valid hid_buffer, it means the transfer was async - if (transfer_priv->hid_dest != NULL) { // Data readout - // First, check for overflow - if (corrected_size > transfer_priv->hid_expected_size) { - usbi_err(ctx, "OVERFLOW!"); - corrected_size = (uint32_t)transfer_priv->hid_expected_size; - r = LIBUSB_TRANSFER_OVERFLOW; - } - - if (transfer_priv->hid_buffer[0] == 0) { - // Discard the 1 byte report ID prefix - corrected_size--; - memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer+1, corrected_size); - } else { - memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, corrected_size); - } - transfer_priv->hid_dest = NULL; - } - // For write, we just need to free the hid buffer - safe_free(transfer_priv->hid_buffer); - } - itransfer->transferred += corrected_size; - return r; -} - - -/* - * Composite API functions - */ -static int composite_init(int sub_api, struct libusb_context *ctx) -{ - return LIBUSB_SUCCESS; -} - -static int composite_exit(int sub_api) -{ - return LIBUSB_SUCCESS; -} - -static int composite_open(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - int r = LIBUSB_ERROR_NOT_FOUND; - uint8_t i; - // SUB_API_MAX+1 as the SUB_API_MAX pos is used to indicate availability of HID - bool available[SUB_API_MAX+1] = {0}; - - for (i=0; i<USB_MAXINTERFACES; i++) { - switch (priv->usb_interface[i].apib->id) { - case USB_API_WINUSBX: - if (priv->usb_interface[i].sub_api != SUB_API_NOTSET) - available[priv->usb_interface[i].sub_api] = true; - break; - case USB_API_HID: - available[SUB_API_MAX] = true; - break; - default: - break; - } - } - - for (i=0; i<SUB_API_MAX; i++) { // WinUSB-like drivers - if (available[i]) { - r = usb_api_backend[USB_API_WINUSBX].open(i, dev_handle); - if (r != LIBUSB_SUCCESS) { - return r; - } - } - } - if (available[SUB_API_MAX]) { // HID driver - r = hid_open(SUB_API_NOTSET, dev_handle); - } - return r; -} - -static void composite_close(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - uint8_t i; - bool available[SUB_API_MAX]; - - for (i = 0; i<SUB_API_MAX; i++) { - available[i] = false; - } - - for (i=0; i<USB_MAXINTERFACES; i++) { - if ( (priv->usb_interface[i].apib->id == USB_API_WINUSBX) - && (priv->usb_interface[i].sub_api != SUB_API_NOTSET) ) { - available[priv->usb_interface[i].sub_api] = true; - } - } - - for (i=0; i<SUB_API_MAX; i++) { - if (available[i]) { - usb_api_backend[USB_API_WINUSBX].close(i, dev_handle); - } - } -} - -static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - return priv->usb_interface[iface].apib-> - claim_interface(priv->usb_interface[iface].sub_api, dev_handle, iface); -} - -static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - return priv->usb_interface[iface].apib-> - set_interface_altsetting(priv->usb_interface[iface].sub_api, dev_handle, iface, altsetting); -} - -static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - return priv->usb_interface[iface].apib-> - release_interface(priv->usb_interface[iface].sub_api, dev_handle, iface); -} - -static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int i, pass; - - // Interface shouldn't matter for control, but it does in practice, with Windows' - // restrictions with regards to accessing HID keyboards and mice. Try a 2 pass approach - for (pass = 0; pass < 2; pass++) { - for (i=0; i<USB_MAXINTERFACES; i++) { - if (priv->usb_interface[i].path != NULL) { - if ((pass == 0) && (priv->usb_interface[i].restricted_functionality)) { - usbi_dbg("trying to skip restricted interface #%d (HID keyboard or mouse?)", i); - continue; - } - usbi_dbg("using interface %d", i); - return priv->usb_interface[i].apib->submit_control_transfer(priv->usb_interface[i].sub_api, itransfer); - } - } - } - - usbi_err(ctx, "no libusbx supported interfaces to complete request"); - return LIBUSB_ERROR_NOT_FOUND; -} - -static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int current_interface; - - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); - return LIBUSB_ERROR_NOT_FOUND; - } - - return priv->usb_interface[current_interface].apib-> - submit_bulk_transfer(priv->usb_interface[current_interface].sub_api, itransfer);} - -static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int current_interface; - - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); - return LIBUSB_ERROR_NOT_FOUND; - } - - return priv->usb_interface[current_interface].apib-> - submit_iso_transfer(priv->usb_interface[current_interface].sub_api, itransfer);} - -static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - int current_interface; - - current_interface = interface_by_endpoint(priv, handle_priv, endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); - return LIBUSB_ERROR_NOT_FOUND; - } - - return priv->usb_interface[current_interface].apib-> - clear_halt(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint);} - -static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->usb_interface[transfer_priv->interface_number].apib-> - abort_control(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer);} - -static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->usb_interface[transfer_priv->interface_number].apib-> - abort_transfers(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer);} - -static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - int r; - uint8_t i; - bool available[SUB_API_MAX]; - for (i = 0; i<SUB_API_MAX; i++) { - available[i] = false; - } - for (i=0; i<USB_MAXINTERFACES; i++) { - if ( (priv->usb_interface[i].apib->id == USB_API_WINUSBX) - && (priv->usb_interface[i].sub_api != SUB_API_NOTSET) ) { - available[priv->usb_interface[i].sub_api] = true; - } - } - for (i=0; i<SUB_API_MAX; i++) { - if (available[i]) { - r = usb_api_backend[USB_API_WINUSBX].reset_device(i, dev_handle); - if (r != LIBUSB_SUCCESS) { - return r; - } - } - } - return LIBUSB_SUCCESS; -} - -static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->usb_interface[transfer_priv->interface_number].apib-> - copy_transfer_data(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer, io_size); -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/os/windows_usb.h b/src/3rd_party-static/libusbx-1.0.16/libusb/os/windows_usb.h deleted file mode 100644 index 5d67a562e8..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/os/windows_usb.h +++ /dev/null @@ -1,918 +0,0 @@ -/* - * Windows backend for libusbx 1.0 - * 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 - -#include "windows_common.h" - -#if defined(_MSC_VER) -// disable /W4 MSVC warnings that are benign -#pragma warning(disable:4127) // conditional expression is constant -#pragma warning(disable:4100) // unreferenced formal parameter -#pragma warning(disable:4214) // bit field types other than int -#pragma warning(disable:4201) // nameless struct/union -#endif - -// Missing from MSVC6 setupapi.h -#if !defined(SPDRP_ADDRESS) -#define SPDRP_ADDRESS 28 -#endif -#if !defined(SPDRP_INSTALL_STATE) -#define SPDRP_INSTALL_STATE 34 -#endif - -#if defined(__CYGWIN__ ) -#define _stricmp stricmp -// cygwin produces a warning unless these prototypes are defined -extern int _snprintf(char *buffer, size_t count, const char *format, ...); -extern char *_strdup(const char *strSource); -// _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread -#define _beginthreadex(a, b, c, d, e, f) CreateThread(a, b, (LPTHREAD_START_ROUTINE)c, d, e, f) -#endif - -#define MAX_CTRL_BUFFER_LENGTH 4096 -#define MAX_USB_DEVICES 256 -#define MAX_USB_STRING_LENGTH 128 -#define MAX_HID_REPORT_SIZE 1024 -#define MAX_HID_DESCRIPTOR_SIZE 256 -#define MAX_GUID_STRING_LENGTH 40 -#define MAX_PATH_LENGTH 128 -#define MAX_KEY_LENGTH 256 -#define LIST_SEPARATOR ';' -#define HTAB_SIZE 1021 - -// Handle code for HID interface that have been claimed ("dibs") -#define INTERFACE_CLAIMED ((HANDLE)(intptr_t)0xD1B5) -// Additional return code for HID operations that completed synchronously -#define LIBUSB_COMPLETED (LIBUSB_SUCCESS + 1) - -// http://msdn.microsoft.com/en-us/library/ff545978.aspx -// http://msdn.microsoft.com/en-us/library/ff545972.aspx -// http://msdn.microsoft.com/en-us/library/ff545982.aspx -#if !defined(GUID_DEVINTERFACE_USB_HOST_CONTROLLER) -const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27} }; -#endif -#if !defined(GUID_DEVINTERFACE_USB_DEVICE) -const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED} }; -#endif -#if !defined(GUID_DEVINTERFACE_USB_HUB) -const GUID GUID_DEVINTERFACE_USB_HUB = { 0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8} }; -#endif -#if !defined(GUID_DEVINTERFACE_LIBUSB0_FILTER) -const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9} }; -#endif - - -/* - * Multiple USB API backend support - */ -#define USB_API_UNSUPPORTED 0 -#define USB_API_HUB 1 -#define USB_API_COMPOSITE 2 -#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 { - const uint8_t id; - const char* designation; - const char **driver_name_list; // Driver name, without .sys, e.g. "usbccgp" - const uint8_t nb_driver_names; - 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]; - -#define PRINT_UNSUPPORTED_API(fname) \ - usbi_dbg("unsupported API call for '" \ - #fname "' (unrecognized device driver)"); \ - return LIBUSB_ERROR_NOT_SUPPORTED; - -/* - * private structures definition - * with inline pseudo constructors/destructors - */ - -// TODO (v2+): move hid desc to libusb.h? -struct libusb_hid_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t bcdHID; - uint8_t bCountryCode; - uint8_t bNumDescriptors; - uint8_t bClassDescriptorType; - uint16_t wClassDescriptorLength; -}; -#define LIBUSB_DT_HID_SIZE 9 -#define HID_MAX_CONFIG_DESC_SIZE (LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE \ - + LIBUSB_DT_HID_SIZE + 2 * LIBUSB_DT_ENDPOINT_SIZE) -#define HID_MAX_REPORT_SIZE 1024 -#define HID_IN_EP 0x81 -#define HID_OUT_EP 0x02 -#define LIBUSB_REQ_RECIPIENT(request_type) ((request_type) & 0x1F) -#define LIBUSB_REQ_TYPE(request_type) ((request_type) & (0x03 << 5)) -#define LIBUSB_REQ_IN(request_type) ((request_type) & LIBUSB_ENDPOINT_IN) -#define LIBUSB_REQ_OUT(request_type) (!LIBUSB_REQ_IN(request_type)) - -// The following are used for HID reports IOCTLs -#define HID_CTL_CODE(id) \ - CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_NEITHER, FILE_ANY_ACCESS) -#define HID_BUFFER_CTL_CODE(id) \ - CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_BUFFERED, FILE_ANY_ACCESS) -#define HID_IN_CTL_CODE(id) \ - CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS) -#define HID_OUT_CTL_CODE(id) \ - CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) - -#define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100) -#define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104) -#define IOCTL_HID_SET_FEATURE HID_IN_CTL_CODE(100) -#define IOCTL_HID_SET_OUTPUT_REPORT HID_IN_CTL_CODE(101) - -enum libusb_hid_request_type { - HID_REQ_GET_REPORT = 0x01, - HID_REQ_GET_IDLE = 0x02, - HID_REQ_GET_PROTOCOL = 0x03, - HID_REQ_SET_REPORT = 0x09, - HID_REQ_SET_IDLE = 0x0A, - HID_REQ_SET_PROTOCOL = 0x0B -}; - -enum libusb_hid_report_type { - HID_REPORT_TYPE_INPUT = 0x01, - HID_REPORT_TYPE_OUTPUT = 0x02, - HID_REPORT_TYPE_FEATURE = 0x03 -}; - -struct hid_device_priv { - uint16_t vid; - uint16_t pid; - uint8_t config; - uint8_t nb_interfaces; - bool uses_report_ids[3]; // input, ouptput, feature - uint16_t input_report_size; - uint16_t output_report_size; - uint16_t feature_report_size; - WCHAR string[3][MAX_USB_STRING_LENGTH]; - uint8_t string_index[3]; // man, prod, ser -}; - -typedef struct libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR; -struct windows_device_priv { - uint8_t depth; // distance to HCD - uint8_t port; // port number on the hub - uint8_t active_config; - struct libusb_device *parent_dev; // access to parent is required for usermode ops - struct windows_usb_api_backend const *apib; - char *path; // device interface path - int sub_api; // for WinUSB-like APIs - struct { - char *path; // each interface needs a device interface path, - 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) - 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]; - struct hid_device_priv *hid; - USB_DEVICE_DESCRIPTOR dev_descriptor; - unsigned char **config_descriptor; // list of pointers to the cached config descriptors -}; - -static inline struct windows_device_priv *_device_priv(struct libusb_device *dev) { - return (struct windows_device_priv *)dev->os_priv; -} - -static inline void windows_device_priv_init(libusb_device* dev) { - struct windows_device_priv* p = _device_priv(dev); - int i; - p->depth = 0; - p->port = 0; - p->parent_dev = NULL; - p->path = NULL; - p->apib = &usb_api_backend[USB_API_UNSUPPORTED]; - p->sub_api = SUB_API_NOTSET; - p->hid = NULL; - p->active_config = 0; - p->config_descriptor = NULL; - memset(&(p->dev_descriptor), 0, sizeof(USB_DEVICE_DESCRIPTOR)); - for (i=0; i<USB_MAXINTERFACES; i++) { - p->usb_interface[i].path = NULL; - p->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED]; - p->usb_interface[i].sub_api = SUB_API_NOTSET; - p->usb_interface[i].nb_endpoints = 0; - p->usb_interface[i].endpoint = NULL; - p->usb_interface[i].restricted_functionality = false; - } -} - -static inline void windows_device_priv_release(libusb_device* dev) { - struct windows_device_priv* p = _device_priv(dev); - int i; - safe_free(p->path); - if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) { - for (i=0; i < dev->num_configurations; i++) - safe_free(p->config_descriptor[i]); - } - safe_free(p->config_descriptor); - safe_free(p->hid); - for (i=0; i<USB_MAXINTERFACES; i++) { - safe_free(p->usb_interface[i].path); - safe_free(p->usb_interface[i].endpoint); - } -} - -struct interface_handle_t { - HANDLE dev_handle; // WinUSB needs an extra handle for the file - HANDLE api_handle; // used by the API to communicate with the device -}; - -struct windows_device_handle_priv { - int active_interface; - struct interface_handle_t interface_handle[USB_MAXINTERFACES]; - int autoclaim_count[USB_MAXINTERFACES]; // For auto-release -}; - -static inline struct windows_device_handle_priv *_device_handle_priv( - struct libusb_device_handle *handle) -{ - return (struct windows_device_handle_priv *) handle->os_priv; -} - -// used for async polling functions -struct windows_transfer_priv { - struct winfd pollable_fd; - uint8_t interface_number; - uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID - uint8_t *hid_dest; // transfer buffer destination, required for HID - size_t hid_expected_size; -}; - -// used to match a device driver (including filter drivers) against a supported API -struct driver_lookup { - char list[MAX_KEY_LENGTH+1];// REG_MULTI_SZ list of services (driver) names - const DWORD reg_prop; // SPDRP registry key to use to retreive list - const char* designation; // internal designation (for debug output) -}; - -/* OLE32 dependency */ -DLL_DECLARE_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID)); - -/* SetupAPI dependencies */ -DLL_DECLARE_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (const GUID*, PCSTR, HWND, DWORD)); -DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA)); -DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA, - const GUID*, DWORD, PSP_DEVICE_INTERFACE_DATA)); -DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, - PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA)); -DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO)); -DLL_DECLARE_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM)); -DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO, - PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD)); -DLL_DECLARE_PREFIXED(WINAPI, 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, RegCloseKey, (HKEY)); - -/* - * Windows DDK API definitions. Most of it copied from MinGW's includes - */ -typedef DWORD DEVNODE, DEVINST; -typedef DEVNODE *PDEVNODE, *PDEVINST; -typedef DWORD RETURN_TYPE; -typedef RETURN_TYPE CONFIGRET; - -#define CR_SUCCESS 0x00000000 -#define CR_NO_SUCH_DEVNODE 0x0000000D - -#define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE -#define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG -#define USB_STRING_DESCRIPTOR_TYPE LIBUSB_DT_STRING -#define USB_INTERFACE_DESCRIPTOR_TYPE LIBUSB_DT_INTERFACE -#define USB_ENDPOINT_DESCRIPTOR_TYPE LIBUSB_DT_ENDPOINT - -#define USB_REQUEST_GET_STATUS LIBUSB_REQUEST_GET_STATUS -#define USB_REQUEST_CLEAR_FEATURE LIBUSB_REQUEST_CLEAR_FEATURE -#define USB_REQUEST_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE -#define USB_REQUEST_SET_ADDRESS LIBUSB_REQUEST_SET_ADDRESS -#define USB_REQUEST_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR -#define USB_REQUEST_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR -#define USB_REQUEST_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION -#define USB_REQUEST_SET_CONFIGURATION LIBUSB_REQUEST_SET_CONFIGURATION -#define USB_REQUEST_GET_INTERFACE LIBUSB_REQUEST_GET_INTERFACE -#define USB_REQUEST_SET_INTERFACE LIBUSB_REQUEST_SET_INTERFACE -#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME - -#define USB_GET_NODE_INFORMATION 258 -#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260 -#define USB_GET_NODE_CONNECTION_NAME 261 -#define USB_GET_HUB_CAPABILITIES 271 -#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX) -#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274 -#endif -#if !defined(USB_GET_HUB_CAPABILITIES_EX) -#define USB_GET_HUB_CAPABILITIES_EX 276 -#endif - -#ifndef METHOD_BUFFERED -#define METHOD_BUFFERED 0 -#endif -#ifndef FILE_ANY_ACCESS -#define FILE_ANY_ACCESS 0x00000000 -#endif -#ifndef FILE_DEVICE_UNKNOWN -#define FILE_DEVICE_UNKNOWN 0x00000022 -#endif -#ifndef FILE_DEVICE_USB -#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN -#endif - -#ifndef CTL_CODE -#define CTL_CODE(DeviceType, Function, Method, Access)( \ - ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) -#endif - -typedef enum USB_CONNECTION_STATUS { - NoDeviceConnected, - DeviceConnected, - DeviceFailedEnumeration, - DeviceGeneralFailure, - DeviceCausedOvercurrent, - DeviceNotEnoughPower, - DeviceNotEnoughBandwidth, - DeviceHubNestedTooDeeply, - DeviceInLegacyHub -} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS; - -typedef enum USB_HUB_NODE { - UsbHub, - UsbMIParent -} USB_HUB_NODE; - -/* Cfgmgr32.dll interface */ -DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG)); -DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG)); -DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG)); -DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG)); - -#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \ - CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_HUB_CAPABILITIES \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_ROOT_HUB_NAME \ - CTL_CODE(FILE_DEVICE_USB, HCD_GET_ROOT_HUB_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_INFORMATION \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_ATTRIBUTES, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_NAME \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// Most of the structures below need to be packed -#pragma pack(push, 1) - -typedef struct USB_INTERFACE_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - UCHAR bInterfaceNumber; - UCHAR bAlternateSetting; - UCHAR bNumEndpoints; - UCHAR bInterfaceClass; - UCHAR bInterfaceSubClass; - UCHAR bInterfaceProtocol; - UCHAR iInterface; -} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR; - -typedef struct USB_CONFIGURATION_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - USHORT wTotalLength; - UCHAR bNumInterfaces; - UCHAR bConfigurationValue; - UCHAR iConfiguration; - UCHAR bmAttributes; - UCHAR MaxPower; -} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR; - -typedef struct USB_CONFIGURATION_DESCRIPTOR_SHORT { - struct { - ULONG ConnectionIndex; - struct { - UCHAR bmRequest; - UCHAR bRequest; - USHORT wValue; - USHORT wIndex; - USHORT wLength; - } SetupPacket; - } req; - USB_CONFIGURATION_DESCRIPTOR data; -} USB_CONFIGURATION_DESCRIPTOR_SHORT; - -typedef struct USB_ENDPOINT_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - UCHAR bEndpointAddress; - UCHAR bmAttributes; - USHORT wMaxPacketSize; - UCHAR bInterval; -} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR; - -typedef struct USB_DESCRIPTOR_REQUEST { - ULONG ConnectionIndex; - struct { - UCHAR bmRequest; - UCHAR bRequest; - USHORT wValue; - USHORT wIndex; - USHORT wLength; - } SetupPacket; -// UCHAR Data[0]; -} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; - -typedef struct USB_HUB_DESCRIPTOR { - UCHAR bDescriptorLength; - UCHAR bDescriptorType; - UCHAR bNumberOfPorts; - USHORT wHubCharacteristics; - UCHAR bPowerOnToPowerGood; - UCHAR bHubControlCurrent; - UCHAR bRemoveAndPowerMask[64]; -} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR; - -typedef struct USB_ROOT_HUB_NAME { - ULONG ActualLength; - WCHAR RootHubName[1]; -} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME; - -typedef struct USB_ROOT_HUB_NAME_FIXED { - ULONG ActualLength; - WCHAR RootHubName[MAX_PATH_LENGTH]; -} USB_ROOT_HUB_NAME_FIXED; - -typedef struct USB_NODE_CONNECTION_NAME { - ULONG ConnectionIndex; - ULONG ActualLength; - WCHAR NodeName[1]; -} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME; - -typedef struct USB_NODE_CONNECTION_NAME_FIXED { - ULONG ConnectionIndex; - ULONG ActualLength; - WCHAR NodeName[MAX_PATH_LENGTH]; -} USB_NODE_CONNECTION_NAME_FIXED; - -typedef struct USB_HUB_NAME_FIXED { - union { - USB_ROOT_HUB_NAME_FIXED root; - USB_NODE_CONNECTION_NAME_FIXED node; - } u; -} USB_HUB_NAME_FIXED; - -typedef struct USB_HUB_INFORMATION { - USB_HUB_DESCRIPTOR HubDescriptor; - BOOLEAN HubIsBusPowered; -} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION; - -typedef struct USB_MI_PARENT_INFORMATION { - ULONG NumberOfInterfaces; -} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION; - -typedef struct USB_NODE_INFORMATION { - USB_HUB_NODE NodeType; - union { - USB_HUB_INFORMATION HubInformation; - USB_MI_PARENT_INFORMATION MiParentInformation; - } u; -} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION; - -typedef struct USB_PIPE_INFO { - USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; - ULONG ScheduleOffset; -} USB_PIPE_INFO, *PUSB_PIPE_INFO; - -typedef struct USB_NODE_CONNECTION_INFORMATION_EX { - ULONG ConnectionIndex; - USB_DEVICE_DESCRIPTOR DeviceDescriptor; - UCHAR CurrentConfigurationValue; - UCHAR Speed; - BOOLEAN DeviceIsHub; - USHORT DeviceAddress; - ULONG NumberOfOpenPipes; - USB_CONNECTION_STATUS ConnectionStatus; -// USB_PIPE_INFO PipeList[0]; -} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; - -typedef struct USB_HUB_CAP_FLAGS { - ULONG HubIsHighSpeedCapable:1; - ULONG HubIsHighSpeed:1; - ULONG HubIsMultiTtCapable:1; - ULONG HubIsMultiTt:1; - ULONG HubIsRoot:1; - ULONG HubIsArmedWakeOnConnect:1; - ULONG ReservedMBZ:26; -} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS; - -typedef struct USB_HUB_CAPABILITIES { - ULONG HubIs2xCapable : 1; -} USB_HUB_CAPABILITIES, *PUSB_HUB_CAPABILITIES; - -typedef struct USB_HUB_CAPABILITIES_EX { - USB_HUB_CAP_FLAGS CapabilityFlags; -} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX; - -#pragma pack(pop) - -/* winusb.dll interface */ - -#define SHORT_PACKET_TERMINATE 0x01 -#define AUTO_CLEAR_STALL 0x02 -#define PIPE_TRANSFER_TIMEOUT 0x03 -#define IGNORE_SHORT_PACKETS 0x04 -#define ALLOW_PARTIAL_READS 0x05 -#define AUTO_FLUSH 0x06 -#define RAW_IO 0x07 -#define MAXIMUM_TRANSFER_SIZE 0x08 -#define AUTO_SUSPEND 0x81 -#define SUSPEND_DELAY 0x83 -#define DEVICE_SPEED 0x01 -#define LowSpeed 0x01 -#define FullSpeed 0x02 -#define HighSpeed 0x03 - -typedef enum USBD_PIPE_TYPE { - UsbdPipeTypeControl, - UsbdPipeTypeIsochronous, - UsbdPipeTypeBulk, - UsbdPipeTypeInterrupt -} USBD_PIPE_TYPE; - -typedef struct { - USBD_PIPE_TYPE PipeType; - UCHAR PipeId; - USHORT MaximumPacketSize; - UCHAR Interval; -} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION; - -#pragma pack(1) -typedef struct { - UCHAR request_type; - UCHAR request; - USHORT value; - USHORT index; - USHORT length; -} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; -#pragma pack() - -typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; - -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)); diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/strerror.c b/src/3rd_party-static/libusbx-1.0.16/libusb/strerror.c deleted file mode 100644 index a3c3afa3fc..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/strerror.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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]; -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/sync.c b/src/3rd_party-static/libusbx-1.0.16/libusb/sync.c deleted file mode 100644 index 42e486db39..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/sync.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * 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 - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include <errno.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#include "libusbi.h" - -/** - * @defgroup syncio Synchronous device I/O - * - * This page documents libusbx's synchronous (blocking) API for USB device I/O. - * This interface is easy to use but has some limitations. More advanced users - * may wish to consider using the \ref asyncio "asynchronous I/O API" instead. - */ - -static void LIBUSB_CALL sync_transfer_cb(struct libusb_transfer *transfer) -{ - int *completed = transfer->user_data; - *completed = 1; - usbi_dbg("actual_length=%d", transfer->actual_length); - /* caller interprets result and frees transfer */ -} - -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 - * Perform a USB control transfer. - * - * The direction of the transfer is inferred from the bmRequestType field of - * the setup packet. - * - * The wValue, wIndex and wLength fields values should be given in host-endian - * byte order. - * - * \param dev_handle a handle for the device to communicate with - * \param bmRequestType the request type field for the setup packet - * \param bRequest the request field for the setup packet - * \param wValue the value field for the setup packet - * \param wIndex the index field for the setup packet - * \param data a suitably-sized data buffer for either input or output - * (depending on direction bits within bmRequestType) - * \param wLength the length field for the setup packet. The data buffer should - * be at least this size. - * \param timeout timeout (in millseconds) that this function should wait - * before giving up due to no response being received. For an unlimited - * timeout, use value 0. - * \returns on success, the number of bytes actually transferred - * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out - * \returns LIBUSB_ERROR_PIPE if the control request was not supported by the - * device - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failures - */ -int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle, - uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - unsigned char *data, uint16_t wLength, unsigned int timeout) -{ - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - unsigned char *buffer; - int completed = 0; - int r; - - if (!transfer) - return LIBUSB_ERROR_NO_MEM; - - buffer = (unsigned char*) malloc(LIBUSB_CONTROL_SETUP_SIZE + wLength); - if (!buffer) { - libusb_free_transfer(transfer); - return LIBUSB_ERROR_NO_MEM; - } - - libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, - wLength); - if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) - memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength); - - libusb_fill_control_transfer(transfer, dev_handle, buffer, - sync_transfer_cb, &completed, timeout); - transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER; - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - return r; - } - - sync_transfer_wait_for_completion(transfer); - - if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) - memcpy(data, libusb_control_transfer_get_data(transfer), - transfer->actual_length); - - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - r = transfer->actual_length; - break; - case LIBUSB_TRANSFER_TIMED_OUT: - r = LIBUSB_ERROR_TIMEOUT; - break; - case LIBUSB_TRANSFER_STALL: - r = LIBUSB_ERROR_PIPE; - break; - case LIBUSB_TRANSFER_NO_DEVICE: - r = LIBUSB_ERROR_NO_DEVICE; - break; - case LIBUSB_TRANSFER_OVERFLOW: - r = LIBUSB_ERROR_OVERFLOW; - break; - case LIBUSB_TRANSFER_ERROR: - case LIBUSB_TRANSFER_CANCELLED: - r = LIBUSB_ERROR_IO; - break; - default: - usbi_warn(HANDLE_CTX(dev_handle), - "unrecognised status code %d", transfer->status); - r = LIBUSB_ERROR_OTHER; - } - - libusb_free_transfer(transfer); - return r; -} - -static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *buffer, int length, - int *transferred, unsigned int timeout, unsigned char type) -{ - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - int completed = 0; - int r; - - if (!transfer) - return LIBUSB_ERROR_NO_MEM; - - libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length, - sync_transfer_cb, &completed, timeout); - transfer->type = type; - - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - return r; - } - - sync_transfer_wait_for_completion(transfer); - - *transferred = transfer->actual_length; - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - r = 0; - break; - case LIBUSB_TRANSFER_TIMED_OUT: - r = LIBUSB_ERROR_TIMEOUT; - break; - case LIBUSB_TRANSFER_STALL: - r = LIBUSB_ERROR_PIPE; - break; - case LIBUSB_TRANSFER_OVERFLOW: - r = LIBUSB_ERROR_OVERFLOW; - break; - case LIBUSB_TRANSFER_NO_DEVICE: - r = LIBUSB_ERROR_NO_DEVICE; - break; - case LIBUSB_TRANSFER_ERROR: - case LIBUSB_TRANSFER_CANCELLED: - r = LIBUSB_ERROR_IO; - break; - default: - usbi_warn(HANDLE_CTX(dev_handle), - "unrecognised status code %d", transfer->status); - r = LIBUSB_ERROR_OTHER; - } - - libusb_free_transfer(transfer); - return r; -} - -/** \ingroup syncio - * Perform a USB bulk transfer. The direction of the transfer is inferred from - * the direction bits of the endpoint address. - * - * For bulk reads, the <tt>length</tt> field indicates the maximum length of - * data you are expecting to receive. If less data arrives than expected, - * this function will return that data, so be sure to check the - * <tt>transferred</tt> output parameter. - * - * You should also check the <tt>transferred</tt> parameter for bulk writes. - * Not all of the data may have been written. - * - * Also check <tt>transferred</tt> when dealing with a timeout error code. - * 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 - * 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 - * indicate a complete lack of I/O. - * - * \param dev_handle a handle for the device to communicate with - * \param endpoint the address of a valid endpoint to communicate with - * \param data a suitably-sized data buffer for either input or output - * (depending on endpoint) - * \param length for bulk writes, the number of bytes from data to be sent. for - * bulk reads, the maximum number of bytes to receive into the data buffer. - * \param transferred output location for the number of bytes actually - * transferred. - * \param timeout timeout (in millseconds) that this function should wait - * before giving up due to no response being received. For an unlimited - * timeout, use value 0. - * - * \returns 0 on success (and populates <tt>transferred</tt>) - * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates - * <tt>transferred</tt>) - * \returns LIBUSB_ERROR_PIPE if the endpoint halted - * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see - * \ref packetoverflow - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failures - */ -int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *data, int length, int *transferred, - unsigned int timeout) -{ - return do_sync_bulk_transfer(dev_handle, endpoint, data, length, - transferred, timeout, LIBUSB_TRANSFER_TYPE_BULK); -} - -/** \ingroup syncio - * Perform a USB interrupt transfer. The direction of the transfer is inferred - * from the direction bits of the endpoint address. - * - * For interrupt reads, the <tt>length</tt> field indicates the maximum length - * of data you are expecting to receive. If less data arrives than expected, - * this function will return that data, so be sure to check the - * <tt>transferred</tt> output parameter. - * - * You should also check the <tt>transferred</tt> parameter for interrupt - * writes. Not all of the data may have been written. - * - * Also check <tt>transferred</tt> when dealing with a timeout error code. - * 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 - * 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 - * indicate a complete lack of I/O. - * - * The default endpoint bInterval value is used as the polling interval. - * - * \param dev_handle a handle for the device to communicate with - * \param endpoint the address of a valid endpoint to communicate with - * \param data a suitably-sized data buffer for either input or output - * (depending on endpoint) - * \param length for bulk writes, the number of bytes from data to be sent. for - * bulk reads, the maximum number of bytes to receive into the data buffer. - * \param transferred output location for the number of bytes actually - * transferred. - * \param timeout timeout (in millseconds) that this function should wait - * before giving up due to no response being received. For an unlimited - * timeout, use value 0. - * - * \returns 0 on success (and populates <tt>transferred</tt>) - * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out - * \returns LIBUSB_ERROR_PIPE if the endpoint halted - * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see - * \ref packetoverflow - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other error - */ -int API_EXPORTED libusb_interrupt_transfer( - struct libusb_device_handle *dev_handle, unsigned char endpoint, - unsigned char *data, int length, int *transferred, unsigned int timeout) -{ - return do_sync_bulk_transfer(dev_handle, endpoint, data, length, - transferred, timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT); -} diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/version.h b/src/3rd_party-static/libusbx-1.0.16/libusb/version.h deleted file mode 100644 index cf37de97a5..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/version.h +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is parsed by m4 and windres and RC.EXE so please keep it simple. */ -#include "version_nano.h" -#ifndef LIBUSB_MAJOR -#define LIBUSB_MAJOR 1 -#endif -#ifndef LIBUSB_MINOR -#define LIBUSB_MINOR 0 -#endif -#ifndef LIBUSB_MICRO -#define LIBUSB_MICRO 16 -#endif -#ifndef LIBUSB_NANO -#define LIBUSB_NANO 0 -#endif -/* LIBUSB_RC is the release candidate suffix. Should normally be empty. */ -#ifndef LIBUSB_RC -#define LIBUSB_RC "" -#endif diff --git a/src/3rd_party-static/libusbx-1.0.16/libusb/version_nano.h b/src/3rd_party-static/libusbx-1.0.16/libusb/version_nano.h deleted file mode 100644 index 525cd7d52d..0000000000 --- a/src/3rd_party-static/libusbx-1.0.16/libusb/version_nano.h +++ /dev/null @@ -1 +0,0 @@ -#define LIBUSB_NANO 10774 |