summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPete Batard <pete@akeo.ie>2011-09-09 12:48:58 +0100
committerPete Batard <pete@akeo.ie>2011-09-09 12:48:58 +0100
commit6c72fbff2da8856df10fa67b9eead9114d271dda (patch)
treea8be08608452e1c4fc2e37c089ba97483a83e1ef
parent845f55c90b0e28b822424956d5df0976cf0f7075 (diff)
downloadlibusb-6c72fbff2da8856df10fa67b9eead9114d271dda.tar.gz
merge -> pbr342
-rw-r--r--.gitignore2
-rw-r--r--CMakeLists.txt49
-rw-r--r--cmake/modules/FindCoreFoundation.cmake17
-rw-r--r--cmake/modules/FindIOKit.cmake20
-rw-r--r--cmake/modules/LibFindMacros.cmake99
-rw-r--r--configure.ac9
-rw-r--r--examples/CMakeLists.txt27
-rw-r--r--examples/dpfp.c3
-rw-r--r--examples/dpfp_threaded.c5
-rw-r--r--examples/xusb.c5
-rw-r--r--libusb/CMakeLists.txt100
-rw-r--r--libusb/Makefile.am14
-rw-r--r--libusb/config.cmake97
-rw-r--r--libusb/config.h.cmake37
-rw-r--r--libusb/core.c63
-rw-r--r--libusb/descriptor.c12
-rw-r--r--libusb/io.c13
-rw-r--r--libusb/libusb-1.0.def10
-rw-r--r--libusb/libusb-1.0.pc.cmake11
-rw-r--r--libusb/libusb.h45
-rw-r--r--libusb/libusbi.h9
-rw-r--r--libusb/os/CMakeLists.txt101
-rw-r--r--libusb/os/darwin_usb.c335
-rw-r--r--libusb/os/linux_usbfs.c265
-rw-r--r--libusb/os/poll_windows.c2
-rw-r--r--libusb/os/threads_posix.c55
-rw-r--r--libusb/os/threads_posix.h2
-rw-r--r--libusb/os/threads_windows.h3
-rw-r--r--libusb/os/windows_usb.c14
-rw-r--r--libusb/os/windows_usb.h16
30 files changed, 1240 insertions, 200 deletions
diff --git a/.gitignore b/.gitignore
index d382111..1bb7437 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,7 +16,7 @@ configure
aclocal.m4
compile
config.guess
-config.h*
+config.h
config.log
config.status
config.sub
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..493e3e1
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,49 @@
+cmake_minimum_required(VERSION 2.6)
+
+# Can be removed once CMake >= 2.8.4 is required
+# this has to be set before the project directive
+set(CMAKE_LEGACY_CYGWIN_WIN32 0)
+
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
+
+project(libusb)
+
+option(WITHOUT_EXPERIMENTAL_WARNING "Disable the warning that CMake build is experimental whenever CMake is run" OFF)
+if (NOT WITHOUT_EXPERIMENTAL_WARNING)
+ message(WARNING "The CMake build system is not officially endorsed. Support may or may not be provided on the libusb-devel@sourceforge.net mailing list")
+endif()
+
+option(WITH_SHARED "Build a shared library" ON)
+option(WITH_STATIC "Build a static library" OFF)
+option(WITH_DOCS "Build the documentation" OFF)
+
+option(WITH_DEBUG_LOG "enable debug logging" OFF)
+
+# if debug logging is enabled, by default enable logging
+option(WITH_LOGGING "if false, disable all logging" ON)
+
+# enable examples by default if building with maintainer mode
+option(WITH_EXAMPLES "build example applications" ${WITH_MAINTAINER_MODE})
+
+option(WITHOUT_PTHREADS "force pthreads to not be used. if on, then they are used based on detection logic" OFF)
+
+set(LIBUSB_MAJOR 1)
+set(LIBUSB_MINOR 0)
+set(LIBUSB_MICRO 8)
+
+macro(append_compiler_flags)
+ foreach(FLAG IN ITEMS ${ARGN})
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAG}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAG}")
+ endforeach()
+endmacro()
+
+if (WITH_DOCS)
+ add_subdirectory(docs)
+endif ()
+
+if (WITH_EXAMPLES)
+ add_subdirectory(examples)
+endif()
+
+add_subdirectory(libusb)
diff --git a/cmake/modules/FindCoreFoundation.cmake b/cmake/modules/FindCoreFoundation.cmake
new file mode 100644
index 0000000..d998e89
--- /dev/null
+++ b/cmake/modules/FindCoreFoundation.cmake
@@ -0,0 +1,17 @@
+# CoreFoundation_INCLUDE_DIR
+# CoreFoundation_LIBRARIES
+# CoreFoundation_FOUND
+include(LibFindMacros)
+
+find_path(CoreFoundation_INCLUDE_DIR
+ CoreFoundation.h
+ PATH_SUFFIXES CoreFoundation
+)
+
+find_library(CoreFoundation_LIBRARY
+ NAMES CoreFoundation
+)
+
+set(CoreFoundation_PROCESS_INCLUDES CoreFoundation_INCLUDE_DIR)
+set(CoreFoundation_PROCESS_LIBS CoreFoundation_LIBRARY)
+libfind_process(CoreFoundation)
diff --git a/cmake/modules/FindIOKit.cmake b/cmake/modules/FindIOKit.cmake
new file mode 100644
index 0000000..584e225
--- /dev/null
+++ b/cmake/modules/FindIOKit.cmake
@@ -0,0 +1,20 @@
+# IOKit_INCLUDE_DIR
+# IOKit_LIBRARIES
+# IOKit_FOUND
+include(LibFindMacros)
+
+# IOKit depends on CoreFoundation
+find_package(CoreFoundation REQUIRED)
+
+find_path(IOKit_INCLUDE_DIR
+ IOKitLib.h
+ PATH_SUFFIXES IOKit
+)
+
+find_library(IOKit_LIBRARY
+ NAMES IOKit
+)
+
+set(IOKit_PROCESS_INCLUDES IOKit_INCLUDE_DIR CoreFoundation_INCLUDE_DIR)
+set(IOKit_PROCESS_LIBS IOKit_LIBRARY CoreFoundation_LIBRARIES)
+libfind_process(IOKit)
diff --git a/cmake/modules/LibFindMacros.cmake b/cmake/modules/LibFindMacros.cmake
new file mode 100644
index 0000000..69975c5
--- /dev/null
+++ b/cmake/modules/LibFindMacros.cmake
@@ -0,0 +1,99 @@
+# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments
+# used for the current package. For this to work, the first parameter must be the
+# prefix of the current package, then the prefix of the new package etc, which are
+# passed to find_package.
+macro (libfind_package PREFIX)
+ set (LIBFIND_PACKAGE_ARGS ${ARGN})
+ if (${PREFIX}_FIND_QUIETLY)
+ set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET)
+ endif (${PREFIX}_FIND_QUIETLY)
+ if (${PREFIX}_FIND_REQUIRED)
+ set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED)
+ endif (${PREFIX}_FIND_REQUIRED)
+ find_package(${LIBFIND_PACKAGE_ARGS})
+endmacro (libfind_package)
+
+# CMake developers made the UsePkgConfig system deprecated in the same release (2.6)
+# where they added pkg_check_modules. Consequently I need to support both in my scripts
+# to avoid those deprecated warnings. Here's a helper that does just that.
+# Works identically to pkg_check_modules, except that no checks are needed prior to use.
+macro (libfind_pkg_check_modules PREFIX PKGNAME)
+ if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+ include(UsePkgConfig)
+ pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS)
+ else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+ find_package(PkgConfig)
+ if (PKG_CONFIG_FOUND)
+ pkg_check_modules(${PREFIX} ${PKGNAME})
+ endif (PKG_CONFIG_FOUND)
+ endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
+endmacro (libfind_pkg_check_modules)
+
+# Do the final processing once the paths have been detected.
+# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
+# all the variables, each of which contain one include directory.
+# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
+# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
+# Also handles errors in case library detection was required, etc.
+macro (libfind_process PREFIX)
+ # Skip processing if already processed during this run
+ if (NOT ${PREFIX}_FOUND)
+ # Start with the assumption that the library was found
+ set (${PREFIX}_FOUND TRUE)
+
+ # Process all includes and set _FOUND to false if any are missing
+ foreach (i ${${PREFIX}_PROCESS_INCLUDES})
+ if (${i})
+ set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}})
+ mark_as_advanced(${i})
+ else (${i})
+ set (${PREFIX}_FOUND FALSE)
+ endif (${i})
+ endforeach (i)
+
+ # Process all libraries and set _FOUND to false if any are missing
+ foreach (i ${${PREFIX}_PROCESS_LIBS})
+ if (${i})
+ set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}})
+ mark_as_advanced(${i})
+ else (${i})
+ set (${PREFIX}_FOUND FALSE)
+ endif (${i})
+ endforeach (i)
+
+ # Print message and/or exit on fatal error
+ if (${PREFIX}_FOUND)
+ if (NOT ${PREFIX}_FIND_QUIETLY)
+ message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
+ endif (NOT ${PREFIX}_FIND_QUIETLY)
+ else (${PREFIX}_FOUND)
+ if (${PREFIX}_FIND_REQUIRED)
+ foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS})
+ message("${i}=${${i}}")
+ endforeach (i)
+ message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.")
+ endif (${PREFIX}_FIND_REQUIRED)
+ endif (${PREFIX}_FOUND)
+ endif (NOT ${PREFIX}_FOUND)
+endmacro (libfind_process)
+
+macro(libfind_library PREFIX basename)
+ set(TMP "")
+ if(MSVC80)
+ set(TMP -vc80)
+ endif(MSVC80)
+ if(MSVC90)
+ set(TMP -vc90)
+ endif(MSVC90)
+ set(${PREFIX}_LIBNAMES ${basename}${TMP})
+ if(${ARGC} GREATER 2)
+ set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2})
+ string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES})
+ set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP})
+ endif(${ARGC} GREATER 2)
+ find_library(${PREFIX}_LIBRARY
+ NAMES ${${PREFIX}_LIBNAMES}
+ PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}
+ )
+endmacro(libfind_library)
+
diff --git a/configure.ac b/configure.ac
index 1aa606b..1812089 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,6 +60,7 @@ case $host in
AC_MSG_RESULT([Darwin/Mac OS X])
backend="darwin"
threads="posix"
+ LIBS="${LIBS} -lobjc"
PC_LIBS_PRIVATE="-Wl,-framework,IOKit -Wl,-framework,CoreFoundation"
LTLDFLAGS="${LTLDFLAGS} -Wl,-prebind"
AC_CHECK_HEADERS([poll.h])
@@ -165,12 +166,6 @@ AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build],
[build_examples='no'])
AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != "xno"])
-# Restore gnu89 inline semantics on gcc 4.3 and newer
-saved_cflags="$CFLAGS"
-CFLAGS="$CFLAGS -fgnu89-inline"
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], inline_cflags="-fgnu89-inline", inline_cflags="")
-CFLAGS="$saved_cflags"
-
# check for -fvisibility=hidden compiler support (GCC >= 3.4)
saved_cflags="$CFLAGS"
# -Werror required for cygwin
@@ -197,7 +192,7 @@ AM_CONDITIONAL([HAVE_SIGACTION], [test "x$have_sigaction" = "xyes"])
# headers not available on all platforms but required on others
AC_CHECK_HEADERS([sys/time.h])
-AM_CFLAGS="-std=gnu99 $inline_cflags -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow"
+AM_CFLAGS="-std=gnu99 -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow"
AC_SUBST(VISIBILITY_CFLAGS)
AC_SUBST(AM_CFLAGS)
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 0000000..d73d729
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,27 @@
+include(CheckFunctionExists)
+include(FindThreads)
+
+check_function_exists(sigaction HAVE_SIGACTION)
+
+if (WITH_SHARED)
+ set(LIBUSB_LIBRARY usb-1.0)
+else()
+ set(LIBUSB_LIBRARY usb-1.0-static)
+endif()
+
+include_directories(../libusb)
+
+add_executable(lsusb lsusb.c)
+target_link_libraries(lsusb ${LIBUSB_LIBRARY})
+add_executable(xusb xusb.c)
+target_link_libraries(xusb ${LIBUSB_LIBRARY})
+
+if (HAVE_SIGACTION)
+ add_executable(dpfp dpfp.c)
+ target_link_libraries(dpfp ${LIBUSB_LIBRARY})
+
+ if (CMAKE_USE_PTHREADS_INIT)
+ add_executable(dpfp_threaded dpfp_threaded.c)
+ target_link_libraries(dpfp_threaded ${LIBUSB_LIBRARY})
+ endif()
+endif()
diff --git a/examples/dpfp.c b/examples/dpfp.c
index 07ffe4d..abbe9dc 100644
--- a/examples/dpfp.c
+++ b/examples/dpfp.c
@@ -225,7 +225,6 @@ static int save_to_file(unsigned char *data)
{
FILE *fd;
char filename[64];
- size_t ignore;
sprintf(filename, "finger%d.pgm", img_idx++);
fd = fopen(filename, "w");
@@ -233,7 +232,7 @@ static int save_to_file(unsigned char *data)
return -1;
fputs("P5 384 289 255 ", fd);
- ignore = fwrite(data + 64, 1, 384*289, fd);
+ (void) fwrite(data + 64, 1, 384*289, fd);
fclose(fd);
printf("saved image to %s\n", filename);
return 0;
diff --git a/examples/dpfp_threaded.c b/examples/dpfp_threaded.c
index 7868015..d13d50e 100644
--- a/examples/dpfp_threaded.c
+++ b/examples/dpfp_threaded.c
@@ -91,7 +91,7 @@ static void *poll_thread_main(void *arg)
}
printf("poll thread shutting down\n");
- pthread_exit(NULL);
+ return NULL;
}
static int find_dpfp_device(void)
@@ -254,7 +254,6 @@ static int save_to_file(unsigned char *data)
{
FILE *fd;
char filename[64];
- size_t ignore;
sprintf(filename, "finger%d.pgm", img_idx++);
fd = fopen(filename, "w");
@@ -262,7 +261,7 @@ static int save_to_file(unsigned char *data)
return -1;
fputs("P5 384 289 255 ", fd);
- ignore = fwrite(data + 64, 1, 384*289, fd);
+ (void) fwrite(data + 64, 1, 384*289, fd);
fclose(fd);
printf("saved image to %s\n", filename);
return 0;
diff --git a/examples/xusb.c b/examples/xusb.c
index de23cdd..0d8fc49 100644
--- a/examples/xusb.c
+++ b/examples/xusb.c
@@ -540,6 +540,8 @@ int test_device(uint16_t vid, uint16_t pid)
int iface_detached = -1;
#endif
struct libusb_device_descriptor dev_desc;
+ char* speed_name[5] = { "Unknown", "1.5 Mbit/s (USB 1.0 LowSpeed)", "12 Mbit/s (USB 1.0 FullSpeed)",
+ "480 Mbit/s (USB 2.0 HighSpeed)", "5000 Mbit/s (USB 3.0 SuperSpeed)"};
char string[128];
uint8_t string_index[3]; // indexes of the string descriptors
uint8_t endpoint_in = 0, endpoint_out = 0; // default IN and OUT endpoints
@@ -562,6 +564,9 @@ int test_device(uint16_t vid, uint16_t pid)
}
printf("\n");
}
+ r = libusb_get_device_speed(dev);
+ if ((r<0) || (r>4)) r=0;
+ printf("speed: %s\n", speed_name[r]);
printf("\nReading device descriptor:\n");
CALL_CHECK(libusb_get_device_descriptor(dev, &dev_desc));
diff --git a/libusb/CMakeLists.txt b/libusb/CMakeLists.txt
new file mode 100644
index 0000000..a1b18fa
--- /dev/null
+++ b/libusb/CMakeLists.txt
@@ -0,0 +1,100 @@
+add_subdirectory(os)
+
+include(config.cmake)
+include(FindThreads)
+
+set (LIBUSB_COMMON
+ core.c
+ descriptor.c
+ io.c
+ sync.c
+ libusb-1.0.rc
+ libusb-1.0.def
+)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/os)
+
+if (CMAKE_THREAD_LIBS_INIT)
+ list(APPEND LIBUSB_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+endif()
+
+# The CLEAN_DIRECT_OUTPUT property setting can be removed once CMake >= 2.8.4
+if (WITH_SHARED)
+ add_library(usb-1.0
+ SHARED
+ ${LIBUSB_COMMON}
+ ${LIBUSB_PLATFORM}
+ )
+
+ if (MSVC)
+ set_target_properties(usb-1.0 PROPERTIES PREFIX "lib")
+ set_target_properties(usb-1.0 PROPERTIES IMPORT_PREFIX "lib")
+ set_target_properties(usb-1.0 PROPERTIES IMPORT_SUFFIX ".dll.lib")
+ endif()
+
+ set_target_properties(usb-1.0 PROPERTIES
+ CLEAN_DIRECT_OUTPUT 1
+ PUBLIC_HEADER libusb.h
+ VERSION "${LIBUSB_MAJOR}.${LIBUSB_MINOR}.${LIBUSB_MICRO}"
+ SOVERSION "${LIBUSB_MAJOR}.${LIBUSB_MINOR}.${LIBUSB_MICRO}"
+ )
+
+ if (DEFINED LIBUSB_LIBRARIES)
+ message("Linking shared library against ${LIBUSB_LIBRARIES}")
+ target_link_libraries(usb-1.0
+ ${LIBUSB_LIBRARIES}
+ )
+ endif()
+
+ list(APPEND LIBUSB_LIBTARGETS usb-1.0)
+endif()
+
+if (WITH_STATIC)
+ add_library(usb-1.0-static
+ STATIC
+ ${LIBUSB_COMMON}
+ ${LIBUSB_PLATFORM}
+ )
+
+ set_target_properties(usb-1.0-static PROPERTIES
+ PREFIX "lib"
+ OUTPUT_NAME "usb-1.0"
+ CLEAN_DIRECT_OUTPUT 1
+ PUBLIC_HEADER libusb.h
+ VERSION "${LIBUSB_MAJOR}.${LIBUSB_MINOR}.${LIBUSB_MICRO}"
+ SOVERSION "${LIBUSB_MAJOR}.${LIBUSB_MINOR}.${LIBUSB_MICRO}"
+ )
+
+ if (DEFINED LIBUSB_LIBRARIES)
+ target_link_libraries(usb-1.0-static
+ ${LIBUSB_LIBRARIES}
+ )
+ endif()
+
+ list(APPEND LIBUSB_LIBTARGETS usb-1.0-static)
+endif()
+
+install(TARGETS ${LIBUSB_LIBTARGETS} EXPORT libusb-1
+ PUBLIC_HEADER DESTINATION include/libusb-1.0
+ ARCHIVE DESTINATION lib
+ LIBRARY DESTINATION lib
+ RUNTIME DESTINATION lib
+)
+install(EXPORT libusb-1 DESTINATION lib/libusb)
+
+foreach(LIB IN LISTS LIBUSB_LIBRARIES)
+ if (LIB MATCHES .framework$)
+ get_filename_component(LIB "${LIB}" NAME)
+ set(LIB "-Wl,-framework,${LIB}")
+ elseif (LIB MATCHES .dylib$)
+ get_filename_component(LIBDIR "${LIB}" PATH)
+ get_filename_component(LIB "${LIB}" NAME)
+ string(REGEX REPLACE "lib(.*).dylib$" "\\1" LIB "${LIB}")
+ set(LIB "-L${LIBDIR} -l${LIB}")
+ endif()
+ set(LIBUSB_LIB_DEPENDS "${LIBUSB_LIB_DEPENDS} ${LIB}")
+endforeach()
+
+configure_file(libusb-1.0.pc.cmake "${CMAKE_CURRENT_BINARY_DIR}/libusb-1.0.pc" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libusb-1.0.pc" DESTINATION lib/pkgconfig)
diff --git a/libusb/Makefile.am b/libusb/Makefile.am
index 2b6ca7b..a5a46cd 100644
--- a/libusb/Makefile.am
+++ b/libusb/Makefile.am
@@ -11,7 +11,7 @@ DARWIN_USB_SRC = os/darwin_usb.c
WINDOWS_USB_SRC = os/poll_windows.c os/windows_usb.c libusb-1.0.rc
EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(WINDOWS_USB_SRC) \
- os/threads_windows.c
+ os/threads_posix.c os/threads_windows.c
if OS_LINUX
OS_SRC = $(LINUX_USBFS_SRC)
@@ -25,19 +25,21 @@ endif
if OS_WINDOWS
OS_SRC = $(WINDOWS_USB_SRC)
-if !THREADS_POSIX
-OS_SRC += os/threads_windows.c
-endif
-
.rc.lo:
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(RC) $(RCFLAGS) -I. -i $< -o $@
endif
+if THREADS_POSIX
+THREADS_SRC = os/threads_posix.h os/threads_posix.c
+else
+THREADS_SRC = os/threads_windows.h os/threads_windows.c
+endif
+
libusb_1_0_la_CFLAGS = $(VISIBILITY_CFLAGS) $(AM_CFLAGS) $(THREAD_CFLAGS)
libusb_1_0_la_LDFLAGS = $(LTLDFLAGS)
libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c sync.c $(OS_SRC) \
os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h \
- os/threads_posix.h os/threads_windows.h \
+ $(THREADS_SRC) \
os/poll_posix.h os/poll_windows.h
hdrdir = $(includedir)/libusb-1.0
diff --git a/libusb/config.cmake b/libusb/config.cmake
new file mode 100644
index 0000000..f064121
--- /dev/null
+++ b/libusb/config.cmake
@@ -0,0 +1,97 @@
+include(CheckCXXCompilerFlag)
+include(CheckIncludeFiles)
+include(CheckTypeSize)
+
+if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
+ if (NOT OS_WINDOWS)
+ # mingw appears to print a bunch of warnings about this
+ check_cxx_compiler_flag("-fvisibility=hidden" HAVE_VISIBILITY)
+ endif()
+ check_cxx_compiler_flag("-Wno-pointer-sign" HAVE_WARN_NO_POINTER_SIGN)
+
+ set(_GNU_SOURCE 1 CACHE INTERNAL "" FORCE)
+
+ unset(ADDITIONAL_CC_FLAGS)
+
+ if (HAVE_VISIBILITY)
+ list(APPEND ADDITIONAL_CC_FLAGS -fvisibility=hidden)
+ endif()
+
+ if (HAVE_WARN_NO_POINTER_SIGN)
+ list(APPEND ADDITIONAL_CC_FLAGS -Wno-pointer-sign)
+ endif()
+
+ append_compiler_flags(
+ -std=gnu99
+ -Wall
+ -Wundef
+ -Wunused
+ -Wstrict-prototypes
+ -Werror-implicit-function-declaration
+ -Wshadow
+ ${ADDITIONAL_CC_FLAGS}
+ )
+else(MSVC)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+ append_compiler_flags(/Wp64)
+endif()
+
+check_include_files(sys/timerfd.h USBI_TIMERFD_AVAILABLE)
+check_type_size(struct timespec STRUCT_TIMESPEC)
+
+if (HAVE_VISIBILITY)
+ set(DEFAULT_VISIBILITY "__attribute__((visibility(\"default\")))" CACHE INTERNAL "visibility attribute to function decl" FORCE)
+else()
+ set(DEFAULT_VISIBILITY "" CACHE INTERNAL "visibility attribute to function decl" FORCE)
+endif()
+
+if (NOT WITHOUT_POLL_H)
+ check_include_files(poll.h HAVE_POLL_H)
+else()
+ set(HAVE_POLL_H FALSE CACHE INTERNAL "poll.h explicitely disabled" FORCE)
+endif()
+
+if (HAVE_POLL_H)
+ list(APPEND CMAKE_EXTRA_INCLUDE_FILES "poll.h")
+ check_type_size(nfds_t NFDS_T)
+ unset(CMAKE_EXTRA_INCLUDE_FILES)
+else()
+ set(HAVE_NFDS_T FALSE CACHE INTERNAL "poll.h not found - assuming no nfds_t (windows)" FORCE)
+ set(NFDS_T "" CACHE INTERNAL "" FORCE)
+endif()
+
+if (HAVE_NFDS_T)
+ set(POLL_NFDS_TYPE nfds_t CACHE INTERNAL "the poll nfds types for this platform" FORCE)
+else()
+ set(POLL_NFDS_TYPE "unsigned int" CACHE INTERNAL "the poll nfds for this platform" FORCE)
+endif()
+
+if (OS_WINDOWS)
+ macro(copy_header_if_missing HEADER VARIABLE ALTERNATIVE_DIR)
+ check_include_files(${HEADER} ${VARIABLE})
+ if (NOT ${VARIABLE})
+ message(STATUS "Missing ${HEADER} - grabbing from ${ALTERNATIVE_DIR}")
+ file(COPY "${ALTERNATIVE_DIR}/${HEADER}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/")
+ endif()
+ endmacro()
+
+ # Only VS 2010 has stdint.h
+ copy_header_if_missing(stdint.h HAVE_STDINT_H ../msvc)
+ copy_header_if_missing(inttypes.h HAVE_INTTYPES_H ../msvc)
+endif()
+
+set(ENABLE_DEBUG_LOGGING ${WITH_DEBUG_LOG} CACHE INTERNAL "enable debug logging (WITH_DEBUG_LOGGING)" FORCE)
+set(ENABLE_LOGGING ${WITH_LOGGING} CACHE INTERNAL "enable logging (WITH_LOGGING)" FORCE)
+set(PACKAGE "libusb" CACHE INTERNAL "The package name" FORCE)
+set(PACKAGE_BUGREPORT "libusb-devel@lists.sourceforge.net" CACHE INTERNAL "Where to send bug reports" FORCE)
+set(PACKAGE_VERSION "${LIBUSB_MAJOR}.${LIBUSB_MINOR}.${LIBUSB_MICRO}" CACHE INTERNAL "package version" FORCE)
+set(PACKAGE_STRING "${PACKAGE} ${PACKAGE_VERSION}" CACHE INTERNAL "package string" FORCE)
+set(PACKAGE_URL "http://www.libusb.org" CACHE INTERNAL "package url" FORCE)
+set(PACKAGE_TARNAME "libusb" CACHE INTERNAL "tarball name" FORCE)
+set(VERSION "${PACKAGE_VERSION}" CACHE INTERNAL "version" FORCE)
+
+configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY)
+message(STATUS "Generated configuration file in ${CMAKE_CURRENT_BINARY_DIR}/config.h")
+
+# for generated config.h
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
diff --git a/libusb/config.h.cmake b/libusb/config.h.cmake
new file mode 100644
index 0000000..cc6b3c3
--- /dev/null
+++ b/libusb/config.h.cmake
@@ -0,0 +1,37 @@
+#ifndef LIBUSB_CONFIG_H
+#define LIBUSB_CONFIG_H
+
+#define DEFAULT_VISIBILITY @DEFAULT_VISIBILITY@
+
+#cmakedefine ENABLE_DEBUG_LOGGING
+
+#cmakedefine ENABLE_LOGGING
+
+#define LIBUSB_MAJOR @LIBUSB_MAJOR@
+
+#define LIBUSB_MINOR @LIBUSB_MINOR@
+
+#define LIBUSB_MICRO @LIBUSB_MINOR@
+
+#cmakedefine _GNU_SOURCE 1
+
+#define PACKAGE @PACKAGE@
+#define PACKAGE_BUGREPORT @PACKAGE_BUGREPORT@
+#define PACKAGE_STRING @PACKAGE_STRING@
+#define PACKAGE_URL @PACKAGE_URL@
+#define PACKAGE_VERSION @PACKAGE_VERSION@
+#define PACKAGE_TARNAME @PACKAGE_TARNAME@
+
+#define VERSION @VERSION@
+
+#cmakedefine OS_LINUX
+#cmakedefine OS_DARWIN
+#cmakedefine OS_WINDOWS
+#cmakedefine THREADS_POSIX
+#cmakedefine USBI_TIMERFD_AVAILABLE
+#cmakedefine HAVE_STRUCT_TIMESPEC
+#cmakedefine HAVE_POLL_H
+#cmakedefine HAVE_SYS_TIME_H
+#define POLL_NFDS_TYPE @POLL_NFDS_TYPE@
+
+#endif /* LIBUSB_CONFIG_H */
diff --git a/libusb/core.c b/libusb/core.c
index 4c299c8..d2f67f8 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -533,6 +533,7 @@ struct libusb_device *usbi_alloc_device(struct libusb_context *ctx,
dev->ctx = ctx;
dev->refcnt = 1;
dev->session_data = session_id;
+ dev->speed = LIBUSB_SPEED_UNKNOWN;
memset(&dev->os_priv, 0, priv_size);
usbi_mutex_lock(&ctx->usb_devs_lock);
@@ -775,6 +776,17 @@ unsigned long API_EXPORTED libusb_get_session_id(libusb_device *dev)
return dev->session_data;
}
+/** \ingroup dev
+ * Get the negotiated speed of the device.
+ * \param dev a device
+ * \returns the device speed or LIBUSB_SPEED_UNKNOWN if the OS doesn't know or
+ * support returning the negotiated speed.
+ */
+enum libusb_speed 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)
{
@@ -1108,6 +1120,51 @@ out:
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);
@@ -1322,7 +1379,7 @@ int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev,
int r = 0;
usbi_dbg("interface %d", interface_number);
- if (interface_number >= sizeof(dev->claimed_interfaces) * 8)
+ if (interface_number >= USB_MAXINTERFACES)
return LIBUSB_ERROR_INVALID_PARAM;
usbi_mutex_lock(&dev->lock);
@@ -1359,7 +1416,7 @@ int API_EXPORTED libusb_release_interface(libusb_device_handle *dev,
int r;
usbi_dbg("interface %d", interface_number);
- if (interface_number >= sizeof(dev->claimed_interfaces) * 8)
+ if (interface_number >= USB_MAXINTERFACES)
return LIBUSB_ERROR_INVALID_PARAM;
usbi_mutex_lock(&dev->lock);
@@ -1403,7 +1460,7 @@ int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev,
{
usbi_dbg("interface %d altsetting %d",
interface_number, alternate_setting);
- if (interface_number >= sizeof(dev->claimed_interfaces) * 8)
+ if (interface_number >= USB_MAXINTERFACES)
return LIBUSB_ERROR_INVALID_PARAM;
usbi_mutex_lock(&dev->lock);
diff --git a/libusb/descriptor.c b/libusb/descriptor.c
index 11480e8..d6ec46c 100644
--- a/libusb/descriptor.c
+++ b/libusb/descriptor.c
@@ -257,11 +257,13 @@ static int parse_interface(libusb_context *ctx,
}
/* Did we hit an unexpected descriptor? */
- usbi_parse_descriptor(buffer, "bb", &header, 0);
- if ((size >= DESC_HEADER_LENGTH) &&
- ((header.bDescriptorType == LIBUSB_DT_CONFIG) ||
- (header.bDescriptorType == LIBUSB_DT_DEVICE)))
- return parsed;
+ if (size >= DESC_HEADER_LENGTH) {
+ usbi_parse_descriptor(buffer, "bb", &header, 0);
+ if ((header.bDescriptorType == LIBUSB_DT_CONFIG) ||
+ (header.bDescriptorType == LIBUSB_DT_DEVICE)) {
+ return parsed;
+ }
+ }
if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
usbi_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoints);
diff --git a/libusb/io.c b/libusb/io.c
index bffa484..bc2ef79 100644
--- a/libusb/io.c
+++ b/libusb/io.c
@@ -1022,7 +1022,7 @@ int usbi_io_init(struct libusb_context *ctx)
#endif
usbi_mutex_init(&ctx->flying_transfers_lock, NULL);
#if defined(OS_WINDOWS)
- usbi_mutex_init(&ctx->events_lock, NULL);
+ usbi_mutex_init_recursive(&ctx->events_lock, NULL);
#else
pthread_mutex_init(&ctx->events_lock, &attr);
pthread_mutexattr_destroy(&attr);
@@ -1290,6 +1290,8 @@ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer)
if (r < 0)
r = LIBUSB_ERROR_OTHER;
}
+#else
+ (void)first;
#endif
out:
@@ -1320,9 +1322,16 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer)
usbi_dbg("");
usbi_mutex_lock(&itransfer->lock);
r = usbi_backend->cancel_transfer(itransfer);
- if (r < 0)
+ if (r < 0) {
usbi_err(TRANSFER_CTX(transfer),
"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;
}
diff --git a/libusb/libusb-1.0.def b/libusb/libusb-1.0.def
index 1ae2756..b2f3861 100644
--- a/libusb/libusb-1.0.def
+++ b/libusb/libusb-1.0.def
@@ -240,6 +240,16 @@ EXPORTS
libusb_get_device_list@32 = libusb_get_device_list
libusb_get_device_list@4 = libusb_get_device_list
libusb_get_device_list@8 = libusb_get_device_list
+ libusb_get_device_speed
+ libusb_get_device_speed@0 = libusb_get_device_speed
+ libusb_get_device_speed@12 = libusb_get_device_speed
+ libusb_get_device_speed@16 = libusb_get_device_speed
+ libusb_get_device_speed@20 = libusb_get_device_speed
+ libusb_get_device_speed@24 = libusb_get_device_speed
+ libusb_get_device_speed@28 = libusb_get_device_speed
+ libusb_get_device_speed@32 = libusb_get_device_speed
+ libusb_get_device_speed@4 = libusb_get_device_speed
+ libusb_get_device_speed@8 = libusb_get_device_speed
libusb_get_max_iso_packet_size
libusb_get_max_iso_packet_size@0 = libusb_get_max_iso_packet_size
libusb_get_max_iso_packet_size@12 = libusb_get_max_iso_packet_size
diff --git a/libusb/libusb-1.0.pc.cmake b/libusb/libusb-1.0.pc.cmake
new file mode 100644
index 0000000..6bf58d0
--- /dev/null
+++ b/libusb/libusb-1.0.pc.cmake
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_PREFIX@/lib@
+includedir=@CMAKE_INSTALL_PREFIX@/include@
+
+Name: libusb-1.0
+Description: C API for USB device access from Linux, Mac OS X and Windows userspace
+Version: @VERSION@
+Libs: -L${libdir} -lusb-1.0
+Libs.private: @LIBUSB_LIB_DEPENDS@
+Cflags: -I${includedir}/libusb-1.0
+
diff --git a/libusb/libusb.h b/libusb/libusb.h
index 9799fb5..852a9e3 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -155,11 +155,15 @@ enum libusb_class_code {
/** Human Interface Device class */
LIBUSB_CLASS_HID = 3,
- /** Printer dclass */
+ /** Physical */
+ LIBUSB_CLASS_PHYSICAL = 5,
+
+ /** Printer class */
LIBUSB_CLASS_PRINTER = 7,
- /** Picture transfer protocol class */
- LIBUSB_CLASS_PTP = 6,
+ /** 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,
@@ -170,6 +174,21 @@ enum libusb_class_code {
/** 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,
@@ -675,6 +694,25 @@ typedef struct libusb_device libusb_device;
*/
typedef struct libusb_device_handle libusb_device_handle;
+/** \ingroup dev
+ * Speed codes. Indicates the speed at which the device is operating.
+ */
+enum libusb_speed {
+ /** The OS doesn't report or know the device speed. */
+ LIBUSB_SPEED_UNKNOWN = 0,
+
+ /** The device is operating at low speed (1.5MBit/s). */
+ LIBUSB_SPEED_LOW = 1,
+
+ /** The device is operating at full speed (12MBit/s). */
+ LIBUSB_SPEED_FULL = 2,
+
+ /** The device is operating at high speed (480MBit/s). */
+ LIBUSB_SPEED_HIGH = 3,
+
+ /** The device is operating at super speed (5000MBit/s). */
+ LIBUSB_SPEED_SUPER = 4,
+};
/** \ingroup misc
* Error codes. Most libusb functions return 0 on success or one of these
@@ -900,6 +938,7 @@ uint8_t LIBUSB_CALL libusb_get_port_number(libusb_device *dev);
libusb_device * LIBUSB_CALL libusb_get_parent(libusb_device *dev);
int LIBUSB_CALL libusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t* path, uint8_t path_length);
uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device *dev);
+enum libusb_speed 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,
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 9cf8aa3..5b39903 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -297,6 +297,7 @@ struct libusb_device {
uint8_t device_address;
usbi_mutex_t devaddr_lock;
uint8_t num_configurations;
+ enum libusb_speed speed;
struct list_head list;
unsigned long session_data;
@@ -353,7 +354,13 @@ enum usbi_transfer_flags {
USBI_TRANSFER_TIMED_OUT = 1 << 0,
/* Set by backend submit_transfer() if the OS handles timeout */
- USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 1
+ USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 1,
+
+ /* Cancellation was requested via libusb_cancel_transfer() */
+ USBI_TRANSFER_CANCELLING = 1 << 2,
+
+ /* Operation on the transfer failed because the device disappeared */
+ USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3,
};
#define __USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \
diff --git a/libusb/os/CMakeLists.txt b/libusb/os/CMakeLists.txt
new file mode 100644
index 0000000..1172c9b
--- /dev/null
+++ b/libusb/os/CMakeLists.txt
@@ -0,0 +1,101 @@
+include(FindThreads)
+
+set(PTHREADS_ENABLED FALSE)
+if (CMAKE_USE_PTHREADS_INIT)
+ set(PTHREADS_ENABLED TRUE)
+endif()
+
+if (WIN32 OR "${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
+ set(OS_WINDOWS 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
+
+ # Enable MingW support for RC language (for CMake pre-2.8)
+ if (MINGW)
+ set(CMAKE_RC_COMPILER_INIT windres)
+ set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
+ endif()
+ enable_language(RC)
+
+ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
+ message(STATUS "Detected cygwin")
+ set(PTHREADS_ENABLED TRUE)
+ set(WITHOUT_POLL_H TRUE CACHE INTERNAL "Disable using poll.h even if it's available - use windows poll instead fo cygwin's" FORCE)
+ endif()
+
+ list(APPEND PLATFORM_SRC
+ poll_windows.c
+ windows_usb.c
+ )
+
+ if (PTHREADS_ENABLED AND NOT WITHOUT_PTHREADS)
+ list(APPEND PLATFORM_SRC threads_posix)
+ else()
+ list(APPEND PLATFORM_SRC threads_windows.c)
+ endif()
+elseif (APPLE)
+ # Apple != OSX alone
+ set(OS_DARWIN 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
+
+ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
+ set(PLATFORM_SRC
+ darwin_usb.c
+ threads_posix.c
+ )
+
+ find_package(IOKit REQUIRED)
+ list(APPEND LIBUSB_LIBRARIES ${IOKit_LIBRARIES})
+
+ # Currently only objc_registerThreadWithCollector requires linking against it
+ # which is only for MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+ include(CheckCSourceCompiles)
+ check_c_source_compiles(
+"#include <AvailabilityMacros.h>
+int main()
+{
+#if !(MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)
+#error \"Don't need objc\"
+#endif
+}
+" NEED_OBJC_REGISTER_THREAD_WITH_COLLECTOR)
+
+ if (NEED_OBJC_REGISTER_THREAD_WITH_COLLECTOR)
+ find_library(LIBOBJC objc)
+ if (NOT LIBOBJC)
+ message(SEND_ERROR "Need objc library but can't find it")
+ else()
+ list(APPEND LIBUSB_LIBRARIES ${LIBOBJC})
+ endif()
+ endif()
+ endif()
+elseif (UNIX)
+ # Unix is for all *NIX systems including OSX
+ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+ set(OS_LINUX 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
+
+ set(PLATFORM_SRC
+ linux_usbfs.c
+ threads_posix.c
+ )
+
+ list(APPEND LIBUSB_LIBRARIES rt)
+ endif()
+endif()
+
+if (NOT PLATFORM_SRC)
+ message(FATAL_ERROR "Unsupported platform ${CMAKE_SYSTEM_NAME}. Currently only support Windows, OSX, & Linux.")
+endif()
+
+# the paths are relative to this directory but used in the parent directory,
+# so we have to adjust the paths
+foreach(SRC IN LISTS PLATFORM_SRC)
+ list(APPEND LIBUSB_PLATFORM ${CMAKE_CURRENT_SOURCE_DIR}/${SRC})
+endforeach()
+
+# export one level up so that the generic
+# libusb parts know what the platform bits are supposed to be
+set(LIBUSB_PLATFORM ${LIBUSB_PLATFORM} PARENT_SCOPE)
+set(LIBUSB_LIBRARIES ${LIBUSB_LIBRARIES} PARENT_SCOPE)
+
+if (WITHOUT_PTHREADS)
+ set(PTHREADS_ENABLED FALSE)
+endif()
+set(THREADS_POSIX ${PTHREADS_ENABLED} CACHE INTERNAL "use pthreads" FORCE)
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
index 7a8608f..7f12c24 100644
--- a/libusb/os/darwin_usb.c
+++ b/libusb/os/darwin_usb.c
@@ -1,6 +1,6 @@
/*
* darwin backend for libusb 1.0
- * Copyright (C) 2008-2010 Nathan Hjelm <hjelmn@users.sourceforge.net>
+ * Copyright (C) 2008-2011 Nathan Hjelm <hjelmn@users.sourceforge.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -34,8 +34,13 @@
#include <mach/clock.h>
#include <mach/clock_types.h>
#include <mach/mach_host.h>
-
#include <mach/mach_port.h>
+
+#include <AvailabilityMacros.h>
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+ #include <objc/objc-auto.h>
+#endif
+
#include <IOKit/IOCFBundle.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/IOCFPlugIn.h>
@@ -152,10 +157,32 @@ static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, ui
return -1;
}
-static int usb_setup_device_iterator (
- struct darwin_context_priv* ctx_priv, io_iterator_t * deviceIterator) {
- return IOServiceGetMatchingServices (
- ctx_priv->libusb_darwin_mp, IOServiceMatching (kIOUSBDeviceClassName), deviceIterator);
+static int usb_setup_device_iterator (io_iterator_t *deviceIterator, long location) {
+ CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
+
+ if (!matchingDict)
+ return kIOReturnError;
+
+ if (location) {
+ CFMutableDictionaryRef propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ if (propertyMatchDict) {
+ CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberLongType, &location);
+
+ CFDictionarySetValue (propertyMatchDict, CFSTR(kUSBDevicePropertyLocationID), locationCF);
+ /* release our reference to the CFNumber (CFDictionarySetValue retains it) */
+ CFRelease (locationCF);
+
+ CFDictionarySetValue (matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
+ /* release out reference to the CFMutableDictionaryRef (CFDictionarySetValue retains it) */
+ CFRelease (propertyMatchDict);
+ }
+ /* else we can still proceed as long as the caller accounts for the possibility of other devices in the iterator */
+ }
+
+ return IOServiceGetMatchingServices(libusb_darwin_mp, matchingDict, deviceIterator);
}
static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp) {
@@ -202,7 +229,7 @@ static kern_return_t darwin_get_device (struct darwin_context_priv* ctx_priv,
UInt32 location;
io_iterator_t deviceIterator;
- kresult = usb_setup_device_iterator (ctx_priv, &deviceIterator);
+ kresult = usb_setup_device_iterator (&deviceIterator, dev_location);
if (kresult)
return kresult;
@@ -272,6 +299,7 @@ static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
io_service_t device;
long location;
+ bool locationValid;
CFTypeRef locationCF;
UInt32 message;
@@ -284,10 +312,19 @@ static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
device, CFSTR (kUSBDevicePropertyLocationID),
kCFAllocatorDefault, 0);
- CFNumberGetValue(locationCF, kCFNumberLongType, &location);
- CFRelease (locationCF);
IOObjectRelease (device);
+ if (!locationCF)
+ continue;
+
+ locationValid = CFGetTypeID(locationCF) == CFNumberGetTypeID() &&
+ CFNumberGetValue(locationCF, kCFNumberLongType, &location);
+
+ CFRelease (locationCF);
+
+ if (!locationValid)
+ continue;
+
usbi_mutex_lock(&ctx->open_devs_lock);
list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) {
dpriv = (struct darwin_device_priv *)handle->dev->os_priv;
@@ -319,7 +356,15 @@ static void darwin_clear_iterator (io_iterator_t iter) {
static void *event_thread_main (void *arg0) {
IOReturn kresult;
struct libusb_context *ctx = (struct libusb_context *)arg0;
- struct darwin_context_priv *ctx_priv = __ctx_priv (ctx);
+ struct darwin_context_priv *ctx_priv = __ctx_priv (ctx); CFRunLoopRef runloop;
+
+ /* Tell the Objective-C garbage collector about this thread.
+ This is required because, unlike NSThreads, pthreads are
+ not automatically registered. Although we don't use
+ Objective-C, we use CoreFoundation, which does. */
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+ objc_registerThreadWithCollector();
+#endif
/* hotplug (device removal) source */
CFRunLoopSourceRef libusb_notification_cfsource;
@@ -329,7 +374,8 @@ static void *event_thread_main (void *arg0) {
usbi_info (ctx, "creating hotplug event source");
- CFRetain (CFRunLoopGetCurrent ());
+ runloop = CFRunLoopGetCurrent ();
+ CFRetain (runloop);
/* add the notification port to the run loop */
libusb_notification_port =
@@ -360,7 +406,7 @@ static void *event_thread_main (void *arg0) {
if (kresult != kIOReturnSuccess) {
usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult));
- pthread_exit ((void *)kresult);
+ pthread_exit (NULL);
}
/* arm notifiers */
@@ -380,11 +426,11 @@ static void *event_thread_main (void *arg0) {
CFRunLoopSourceInvalidate (libusb_notification_cfsource);
IONotificationPortDestroy (libusb_notification_port);
- CFRelease (CFRunLoopGetCurrent ());
+ CFRelease (runloop);
ctx_priv->libusb_darwin_acfl = NULL;
- pthread_exit (0);
+ pthread_exit (NULL);
}
static int darwin_init(struct libusb_context *ctx) {
@@ -422,12 +468,10 @@ static int darwin_init(struct libusb_context *ctx) {
static void darwin_exit (libusb_context* ctx) {
struct darwin_context_priv *ctx_priv = __ctx_priv (ctx);
if (!(--ctx_priv->initCount)) {
- void *ret;
/* stop the async runloop */
- CFRunLoopStop (ctx_priv->libusb_darwin_acfl);
- /* TODO: pthread_join -> usbi_join? */
- pthread_join (ctx_priv->libusb_darwin_at, &ret);
+ CFRunLoopStop (libusb_darwin_acfl);
+ pthread_join (libusb_darwin_at, NULL);
if (ctx_priv->libusb_darwin_mp)
mach_port_deallocate(mach_task_self(), ctx_priv->libusb_darwin_mp);
@@ -525,91 +569,225 @@ static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t confi
return darwin_to_libusb (kresult);
}
-static int add_new_device (
- struct libusb_context *ctx, usb_device_t **device, UInt32 locationID,
- struct libusb_device **dev)
-{
- struct darwin_device_priv *priv;
- UInt16 address, idVendor, idProduct;
- UInt8 bDeviceClass, bDeviceSubClass;
- IOUSBDevRequest req;
- int ret = 0, need_unref = 0;
+/* check whether the os has configured the device */
+static int darwin_check_configuration (struct libusb_context *ctx, struct libusb_device *dev, usb_device_t **darwin_device) {
+ struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv;
- usbi_info (ctx, "allocating new device for location 0x%08x", locationID);
- *dev = usbi_alloc_device(ctx, locationID);
+ IOUSBConfigurationDescriptorPtr configDesc;
+ IOUSBFindInterfaceRequest request;
+ kern_return_t kresult;
+ io_iterator_t interface_iterator;
+ io_service_t firstInterface;
- if (!*dev) {
- return LIBUSB_ERROR_NO_MEM;
+ if (priv->dev_descriptor.bNumConfigurations < 1) {
+ usbi_err (ctx, "device has no configurations");
+ return LIBUSB_ERROR_OTHER; /* no configurations at this speed so we can't use it */
}
- priv = (struct darwin_device_priv *)(*dev)->os_priv;
+ /* find the first configuration */
+ kresult = (*darwin_device)->GetConfigurationDescriptorPtr (darwin_device, 0, &configDesc);
+ priv->first_config = (kIOReturnSuccess == kresult) ? configDesc->bConfigurationValue : 1;
+
+ /* check if the device is already configured. there is probably a better way than iterating over the
+ to accomplish this (the trick is we need to avoid a call to GetConfigurations since buggy devices
+ might lock up on the device request) */
+
+ /* Setup the Interface Request */
+ request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+ request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+ kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator);
+ if (kresult)
+ return darwin_to_libusb (kresult);
+
+ /* iterate once */
+ firstInterface = IOIteratorNext(interface_iterator);
+
+ /* done with the interface iterator */
+ IOObjectRelease(interface_iterator);
+
+ if (firstInterface) {
+ IOObjectRelease (firstInterface);
+
+ /* device is configured */
+ if (priv->dev_descriptor.bNumConfigurations == 1)
+ /* to avoid problems with some devices get the configurations value from the configuration descriptor */
+ priv->active_config = priv->first_config;
+ else
+ /* devices with more than one configuration should work with GetConfiguration */
+ (*darwin_device)->GetConfiguration (darwin_device, &priv->active_config);
+ } else
+ /* not configured */
+ priv->active_config = 0;
+
+ usbi_info (ctx, "active config: %u, first config: %u", priv->active_config, priv->first_config);
+
+ return 0;
+}
+
+static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct libusb_device *dev, usb_device_t **device) {
+ struct darwin_device_priv *priv;
+ int retries = 5, delay = 30000;
+ int unsuspended = 0, try_unsuspend = 1, try_reconfigure = 1;
+ int is_open = 0;
+ int ret = 0, ret2;
+ IOUSBDevRequest req;
+ UInt8 bDeviceClass;
+ UInt16 idProduct, idVendor;
+
+ (*device)->GetDeviceClass (device, &bDeviceClass);
+ (*device)->GetDeviceProduct (device, &idProduct);
+ (*device)->GetDeviceVendor (device, &idVendor);
+
+ priv = (struct darwin_device_priv *)dev->os_priv;
+
+ /* try to open the device (we can usually continue even if this fails) */
+ is_open = ((*device)->USBDeviceOpenSeize(device) == kIOReturnSuccess);
+ /**** retrieve device descriptor ****/
+ do {
/* Set up request for device descriptor */
+ memset (&(priv->dev_descriptor), 0, sizeof(IOUSBDeviceDescriptor));
req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
req.bRequest = kUSBRqGetDescriptor;
req.wValue = kUSBDeviceDesc << 8;
req.wIndex = 0;
- req.wLength = sizeof(IOUSBDeviceDescriptor);
+ req.wLength = sizeof(priv->dev_descriptor);
req.pData = &(priv->dev_descriptor);
- (*(device))->GetDeviceAddress (device, (USBDeviceAddress *)&address);
- (*(device))->GetDeviceProduct (device, &idProduct);
- (*(device))->GetDeviceVendor (device, &idVendor);
- (*(device))->GetDeviceClass (device, &bDeviceClass);
- (*(device))->GetDeviceSubClass (device, &bDeviceSubClass);
-
- /**** retrieve device descriptors ****/
- /* device must be open for DeviceRequest */
- (*device)->USBDeviceOpen(device);
+ /* according to Apple's documentation the device must be open for DeviceRequest but we may not be able to open some
+ * devices and Apple's USB Prober doesn't bother to open the device before issuing a descriptor request. Still,
+ * to follow the spec as closely as possible, try opening the device */
ret = (*(device))->DeviceRequest (device, &req);
- if (ret != kIOReturnSuccess) {
- int try_unsuspend = 1;
+
+ if (kIOReturnOverrun == ret && kUSBDeviceDesc == priv->dev_descriptor.bDescriptorType)
+ /* received an overrun error but we still received a device descriptor */
+ ret = kIOReturnSuccess;
+
+ if (kIOReturnSuccess == ret && (0 == priv->dev_descriptor.idProduct ||
+ 0 == priv->dev_descriptor.bNumConfigurations ||
+ 0 == priv->dev_descriptor.bcdUSB)) {
+ /* work around for incorrectly configured devices */
+ if (try_reconfigure && is_open) {
+ usbi_dbg("descriptor appears to be invalid. resetting configuration before trying again...");
+
+ /* set the first configuration */
+ (*device)->SetConfiguration(device, 1);
+
+ /* don't try to reconfigure again */
+ try_reconfigure = 0;
+ }
+
+ ret = kIOUSBPipeStalled;
+ }
+
+ if (kIOReturnSuccess != ret && is_open && try_unsuspend) {
+ /* device may be suspended. unsuspend it and try again */
#if DeviceVersion >= 320
UInt32 info;
- /* device may be suspended. unsuspend it and try again */
/* IOUSBFamily 320+ provides a way to detect device suspension but earlier versions do not */
(void)(*device)->GetUSBDeviceInformation (device, &info);
try_unsuspend = info & (1 << kUSBInformationDeviceIsSuspendedBit);
#endif
- /* the device should be open before to device is unsuspended */
- (void) (*device)->USBDeviceOpenSeize(device);
-
if (try_unsuspend) {
/* resume the device */
- (void)(*device)->USBDeviceSuspend (device, 0);
-
- ret = (*(device))->DeviceRequest (device, &req);
-
- /* resuspend the device */
- (void)(*device)->USBDeviceSuspend (device, 1);
+ 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;
}
-
- (*device)->USBDeviceClose (device);
}
- if (ret != kIOReturnSuccess) {
- usbi_warn (ctx, "could not retrieve device descriptor: %s. skipping device", darwin_error_str (ret));
- ret = -1;
- goto end;
+ 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--);
- /**** end: retrieve device descriptors ****/
+ if (unsuspended)
+ /* resuspend the device */
+ (void)(*device)->USBDeviceSuspend (device, 1);
+
+ if (is_open)
+ (void) (*device)->USBDeviceClose (device);
+
+ if (ret != kIOReturnSuccess) {
+ /* a debug message was already printed out for this error */
+ if (LIBUSB_CLASS_HUB == bDeviceClass)
+ usbi_dbg ("could not retrieve device descriptor %.4x:%.4x: %s. skipping device", idVendor, idProduct, darwin_error_str (ret));
+ else
+ usbi_warn (ctx, "could not retrieve device descriptor %.4x:%.4x: %s. skipping device", idVendor, idProduct, darwin_error_str (ret));
- /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices. */
- if (libusb_le16_to_cpu (priv->dev_descriptor.idProduct) != idProduct) {
- /* not a valid device */
- usbi_warn (ctx, "idProduct from iokit (%04x) does not match idProduct in descriptor (%04x). skipping device",
- idProduct, libusb_le16_to_cpu (priv->dev_descriptor.idProduct));
- ret = -1;
+ return -1;
+ }
+
+ usbi_dbg ("device descriptor:");
+ usbi_dbg (" bDescriptorType: 0x%02x", priv->dev_descriptor.bDescriptorType);
+ usbi_dbg (" bcdUSB: 0x%04x", priv->dev_descriptor.bcdUSB);
+ usbi_dbg (" bDeviceClass: 0x%02x", priv->dev_descriptor.bDeviceClass);
+ usbi_dbg (" bDeviceSubClass: 0x%02x", priv->dev_descriptor.bDeviceSubClass);
+ usbi_dbg (" bDeviceProtocol: 0x%02x", priv->dev_descriptor.bDeviceProtocol);
+ usbi_dbg (" bMaxPacketSize0: 0x%02x", priv->dev_descriptor.bMaxPacketSize0);
+ usbi_dbg (" idVendor: 0x%04x", priv->dev_descriptor.idVendor);
+ usbi_dbg (" idProduct: 0x%04x", priv->dev_descriptor.idProduct);
+ usbi_dbg (" bcdDevice: 0x%04x", priv->dev_descriptor.bcdDevice);
+ usbi_dbg (" iManufacturer: 0x%02x", priv->dev_descriptor.iManufacturer);
+ usbi_dbg (" iProduct: 0x%02x", priv->dev_descriptor.iProduct);
+ usbi_dbg (" iSerialNumber: 0x%02x", priv->dev_descriptor.iSerialNumber);
+ usbi_dbg (" bNumConfigurations: 0x%02x", priv->dev_descriptor.bNumConfigurations);
+
+ /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices. */
+ if (libusb_le16_to_cpu (priv->dev_descriptor.idProduct) != idProduct) {
+ /* not a valid device */
+ usbi_warn (ctx, "idProduct from iokit (%04x) does not match idProduct in descriptor (%04x). skipping device",
+ idProduct, libusb_le16_to_cpu (priv->dev_descriptor.idProduct));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int process_new_device (struct libusb_context *ctx, usb_device_t **device, UInt32 locationID, struct discovered_devs **_discdevs) {
+ struct darwin_device_priv *priv;
+ struct libusb_device *dev;
+ struct discovered_devs *discdevs;
+ UInt16 address;
+ UInt8 devSpeed;
+ int ret = 0, need_unref = 0;
+
+ do {
+ dev = usbi_get_device_by_session_id(ctx, locationID);
+ if (!dev) {
+ usbi_info (ctx, "allocating new device for location 0x%08x", locationID);
+ dev = usbi_alloc_device(ctx, locationID);
+ need_unref = 1;
+ } else
+ usbi_info (ctx, "using existing device for location 0x%08x", locationID);
+
+ if (!dev) {
+ ret = LIBUSB_ERROR_NO_MEM;
goto end;
}
- (*dev)->bus_number = locationID >> 24;
- (*dev)->device_address = address;
+ priv = (struct darwin_device_priv *)dev->os_priv;
+
+ (*device)->GetDeviceAddress (device, (USBDeviceAddress *)&address);
+
+ ret = darwin_cache_device_descriptor (ctx, dev, device);
+ if (ret < 0)
+ goto end;
/* check current active configuration (and cache the first configuration value-- which may be used by claim_interface) */
/* TODO: where does this come from???
@@ -617,10 +795,23 @@ static int add_new_device (
if (ret < 0)
break;
*/
+ dev->bus_number = locationID >> 24;
+ dev->device_address = address;
+
+ (*device)->GetDeviceSpeed (device, &devSpeed);
+
+ switch (devSpeed) {
+ case kUSBDeviceSpeedLow: dev->speed = LIBUSB_SPEED_LOW; break;
+ case kUSBDeviceSpeedFull: dev->speed = LIBUSB_SPEED_FULL; break;
+ case kUSBDeviceSpeedHigh: dev->speed = LIBUSB_SPEED_HIGH; break;
+ default:
+ usbi_warn (ctx, "Got unknown device speed %d", devSpeed);
+ }
+
/* save our location, we'll need this later */
priv->location = locationID;
- priv->status_changed = 0;
- snprintf(priv->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", address, idVendor, idProduct, bDeviceClass, bDeviceSubClass);
+ snprintf(priv->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", address, priv->dev_descriptor.idVendor, priv->dev_descriptor.idProduct,
+ priv->dev_descriptor.bDeviceClass, priv->dev_descriptor.bDeviceSubClass);
ret = usbi_sanitize_device (*dev);
@@ -681,7 +872,7 @@ static int darwin_get_device_list(struct libusb_context *ctx, struct discovered_
if (!ctx_priv->libusb_darwin_mp)
return LIBUSB_ERROR_INVALID_PARAM;
- kresult = usb_setup_device_iterator (ctx_priv, &deviceIterator);
+ kresult = usb_setup_device_iterator (&deviceIterator, 0);
if (kresult != kIOReturnSuccess)
return darwin_to_libusb (kresult);
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 9bf49d2..6f1067f 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -24,7 +24,6 @@
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
-#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -96,10 +95,10 @@ static clockid_t monotonic_clkid = -1;
/* do we have a busnum to relate devices? this also implies that we can read
* the active configuration through bConfigurationValue */
-static int sysfs_can_relate_devices = -1;
+static int sysfs_can_relate_devices = 0;
/* do we have a descriptors file? */
-static int sysfs_has_descriptors = -1;
+static int sysfs_has_descriptors = 0;
struct linux_context_priv {
struct udev *udev_ctx;
@@ -254,6 +253,22 @@ static int check_flag_bulk_continuation(void)
return 1;
}
+/* Return 1 if filename exists inside dirname in sysfs.
+ SYSFS_DEVICE_PATH is assumed to be the beginning of the path. */
+static int sysfs_has_file(const char *dirname, const char *filename)
+{
+ struct stat statbuf;
+ char path[PATH_MAX];
+ int r;
+
+ snprintf(path, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH, dirname, filename);
+ r = stat(path, &statbuf);
+ if (r == 0 && S_ISREG(statbuf.st_mode))
+ return 1;
+
+ return 0;
+}
+
static int op_init(struct libusb_context *ctx)
{
struct linux_context_priv* ctx_priv = __ctx_priv(ctx);
@@ -283,7 +298,60 @@ static int op_init(struct libusb_context *ctx)
r = stat(SYSFS_DEVICE_PATH, &statbuf);
if (r == 0 && S_ISDIR(statbuf.st_mode)) {
+ DIR *devices = opendir(SYSFS_DEVICE_PATH);
+ struct dirent *entry;
+
usbi_dbg("found usb devices in sysfs");
+
+ if (!devices) {
+ usbi_err(ctx, "opendir devices failed errno=%d", errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ /* Make sure sysfs supports all the required files. If it
+ * does not, then usbfs will be used instead. Determine
+ * this by looping through the directories in
+ * SYSFS_DEVICE_PATH. With the assumption that there will
+ * always be subdirectories of the name usbN (usb1, usb2,
+ * etc) representing the root hubs, check the usbN
+ * subdirectories to see if they have all the needed files.
+ * This algorithm uses the usbN subdirectories (root hubs)
+ * because a device disconnection will cause a race
+ * condition regarding which files are available, sometimes
+ * causing an incorrect result. The root hubs are used
+ * because it is assumed that they will always be present.
+ * See the "sysfs vs usbfs" comment at the top of this file
+ * for more details. */
+ while ((entry = readdir(devices))) {
+ int has_busnum=0, has_devnum=0, has_descriptors=0;
+ int has_configuration_value=0;
+
+ /* Only check the usbN directories. */
+ if (strncmp(entry->d_name, "usb", 3) != 0)
+ continue;
+
+ /* Check for the files libusb needs from sysfs. */
+ has_busnum = sysfs_has_file(entry->d_name, "busnum");
+ has_devnum = sysfs_has_file(entry->d_name, "devnum");
+ has_descriptors = sysfs_has_file(entry->d_name, "descriptors");
+ has_configuration_value = sysfs_has_file(entry->d_name, "bConfigurationValue");
+
+ if (has_busnum && has_devnum && has_configuration_value)
+ sysfs_can_relate_devices = 1;
+ if (has_descriptors)
+ sysfs_has_descriptors = 1;
+
+ /* Only need to check until we've found ONE device which
+ has all the attributes. */
+ if (sysfs_has_descriptors && sysfs_can_relate_devices)
+ break;
+ }
+ closedir(devices);
+
+ /* Only use sysfs descriptors if the rest of
+ sysfs will work for libusb. */
+ if (!sysfs_can_relate_devices)
+ sysfs_has_descriptors = 0;
} else {
usbi_dbg("sysfs usb info not available");
sysfs_has_descriptors = 0;
@@ -356,6 +424,41 @@ static int __open_sysfs_attr(struct libusb_device *dev, const char *attr)
return fd;
}
+/* Note only suitable for attributes which always read >= 0, < 0 is error */
+static int __read_sysfs_attr(struct libusb_context *ctx,
+ const char *devname, const char *attr)
+{
+ char filename[PATH_MAX];
+ FILE *f;
+ int r, value;
+
+ snprintf(filename, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH,
+ devname, attr);
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ if (errno == ENOENT) {
+ /* File doesn't exist. Assume the device has been
+ disconnected (see trac ticket #70). */
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+ usbi_err(ctx, "open %s failed errno=%d", filename, errno);
+ return LIBUSB_ERROR_IO;
+ }
+
+ r = fscanf(f, "%d", &value);
+ fclose(f);
+ if (r != 1) {
+ usbi_err(ctx, "fscanf %s returned %d, errno=%d", attr, r, errno);
+ return LIBUSB_ERROR_NO_DEVICE; /* For unplug race (trac #70) */
+ }
+ if (value < 0) {
+ usbi_err(ctx, "%s contains a negative value", filename);
+ return LIBUSB_ERROR_IO;
+ }
+
+ return value;
+}
+
static int sysfs_get_device_descriptor(struct libusb_device *dev,
unsigned char *buffer)
{
@@ -730,7 +833,7 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
struct linux_device_priv *priv = __device_priv(dev);
unsigned char *dev_buf;
char path[PATH_MAX];
- int fd;
+ int fd, speed;
int active_config = 0;
int device_configured = 1;
ssize_t r;
@@ -743,6 +846,20 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum,
if (!priv->sysfs_dir)
return LIBUSB_ERROR_NO_MEM;
strcpy(priv->sysfs_dir, sysfs_dir);
+
+ /* Note speed can contain 1.5, in this case __read_sysfs_attr
+ will stop parsing at the '.' and return 1 */
+ speed = __read_sysfs_attr(DEVICE_CTX(dev), sysfs_dir, "speed");
+ if (speed >= 0) {
+ switch (speed) {
+ case 1: dev->speed = LIBUSB_SPEED_LOW; break;
+ case 12: dev->speed = LIBUSB_SPEED_FULL; break;
+ case 480: dev->speed = LIBUSB_SPEED_HIGH; break;
+ case 5000: dev->speed = LIBUSB_SPEED_SUPER; break;
+ default:
+ usbi_warn(DEVICE_CTX(dev), "Unknown device speed: %d Mbps", speed);
+ }
+ }
}
if (sysfs_has_descriptors)
@@ -983,70 +1100,20 @@ out:
}
static int sysfs_scan_device(struct libusb_context *ctx,
- struct discovered_devs **_discdevs, const char *devname,
- int *usbfs_fallback)
+ struct discovered_devs **_discdevs, const char *devname)
{
- int r;
- FILE *fd;
- char filename[PATH_MAX];
int busnum;
int devaddr;
usbi_dbg("scan %s", devname);
- /* determine descriptors presence ahead of time, we need to know this
- * when we reach initialize_device */
- if (sysfs_has_descriptors == -1) {
- struct stat statbuf;
-
- snprintf(filename, PATH_MAX, "%s/%s/descriptors", SYSFS_DEVICE_PATH,
- devname);
- r = stat(filename, &statbuf);
- if (r == 0 && S_ISREG(statbuf.st_mode)) {
- usbi_dbg("sysfs descriptors available");
- sysfs_has_descriptors = 1;
- } else {
- usbi_dbg("sysfs descriptors not available");
- sysfs_has_descriptors = 0;
- }
- }
-
- snprintf(filename, PATH_MAX, "%s/%s/busnum", SYSFS_DEVICE_PATH, devname);
- fd = fopen(filename, "r");
- if (!fd) {
- if (errno == ENOENT) {
- usbi_dbg("busnum not found, cannot relate sysfs to usbfs, "
- "falling back on pure usbfs");
- sysfs_can_relate_devices = 0;
- *usbfs_fallback = 1;
- return LIBUSB_ERROR_OTHER;
- }
- usbi_err(ctx, "open busnum failed, errno=%d", errno);
- return LIBUSB_ERROR_IO;
- }
-
- sysfs_can_relate_devices = 1;
+ busnum = __read_sysfs_attr(ctx, devname, "busnum");
+ if (busnum < 0)
+ return busnum;
- r = fscanf(fd, "%d", &busnum);
- fclose(fd);
- if (r != 1) {
- usbi_err(ctx, "fscanf busnum returned %d, errno=%d", r, errno);
- return LIBUSB_ERROR_IO;
- }
-
- snprintf(filename, PATH_MAX, "%s/%s/devnum", SYSFS_DEVICE_PATH, devname);
- fd = fopen(filename, "r");
- if (!fd) {
- usbi_err(ctx, "open devnum failed, errno=%d", errno);
- return LIBUSB_ERROR_IO;
- }
-
- r = fscanf(fd, "%d", &devaddr);
- fclose(fd);
- if (r != 1) {
- usbi_err(ctx, "fscanf devnum returned %d, errno=%d", r, errno);
- return LIBUSB_ERROR_IO;
- }
+ devaddr = __read_sysfs_attr(ctx, devname, "devnum");
+ if (devaddr < 0)
+ return devaddr;
usbi_dbg("bus=%d dev=%d", busnum, devaddr);
if (busnum > 255 || devaddr > 255)
@@ -1125,7 +1192,7 @@ static void sysfs_analyze_topology(struct discovered_devs *discdevs)
}
static int sysfs_get_device_list(struct libusb_context *ctx,
- struct discovered_devs **_discdevs, int *usbfs_fallback)
+ struct discovered_devs **_discdevs)
{
struct discovered_devs *discdevs = *_discdevs;
DIR *devices = opendir(SYSFS_DEVICE_PATH);
@@ -1144,13 +1211,12 @@ static int sysfs_get_device_list(struct libusb_context *ctx,
|| strchr(entry->d_name, ':'))
continue;
- r = sysfs_scan_device(ctx, &discdevs_new, entry->d_name,
- usbfs_fallback);
- if (r < 0)
+ r = sysfs_scan_device(ctx, &discdevs_new, entry->d_name);
+ if (r < 0 && r != LIBUSB_ERROR_NO_DEVICE)
goto out;
discdevs = discdevs_new;
}
-
+ r = 0;
out:
closedir(devices);
*_discdevs = discdevs;
@@ -1166,19 +1232,15 @@ static int op_get_device_list(struct libusb_context *ctx,
* any autosuspended USB devices. however, sysfs is not available
* everywhere, so we need a usbfs fallback too.
*
- * as described in the "sysfs vs usbfs" comment, sometimes we have
- * sysfs but not enough information to relate sysfs devices to usbfs
- * nodes. the usbfs_fallback variable is used to indicate that we should
- * fall back on usbfs.
+ * 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) {
- int usbfs_fallback = 0;
- int r = sysfs_get_device_list(ctx, _discdevs, &usbfs_fallback);
- if (!usbfs_fallback)
- return r;
- }
-
- return usbfs_get_device_list(ctx, _discdevs);
+ if (sysfs_can_relate_devices != 0)
+ return sysfs_get_device_list(ctx, _discdevs);
+ else
+ return usbfs_get_device_list(ctx, _discdevs);
}
static int op_open(struct libusb_device_handle *handle)
@@ -1222,6 +1284,9 @@ static int op_get_configuration(struct libusb_device_handle *handle,
return LIBUSB_ERROR_NOT_SUPPORTED;
r = sysfs_get_active_config(handle->dev, config);
+ if (r < 0)
+ return r;
+
if (*config == -1)
*config = 0;
@@ -1344,17 +1409,47 @@ static int op_clear_halt(struct libusb_device_handle *handle,
static int op_reset_device(struct libusb_device_handle *handle)
{
int fd = __device_handle_priv(handle)->fd;
- int r = ioctl(fd, IOCTL_USBFS_RESET, NULL);
+ int i, r, ret = 0;
+
+ /* Doing a device reset will cause the usbfs driver to get unbound
+ from any interfaces it is bound to. By voluntarily unbinding
+ the usbfs driver ourself, we stop the kernel from rebinding
+ the interface after reset (which would end up with the interface
+ getting bound to the in kernel driver if any). */
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if (handle->claimed_interfaces & (1L << i)) {
+ op_release_interface(handle, i);
+ }
+ }
+
+ usbi_mutex_lock(&handle->lock);
+ r = ioctl(fd, IOCTL_USBFS_RESET, NULL);
if (r) {
- if (errno == ENODEV)
- return LIBUSB_ERROR_NOT_FOUND;
+ if (errno == ENODEV) {
+ ret = LIBUSB_ERROR_NOT_FOUND;
+ goto out;
+ }
usbi_err(HANDLE_CTX(handle),
"reset failed error %d errno %d", r, errno);
- return LIBUSB_ERROR_OTHER;
+ ret = LIBUSB_ERROR_OTHER;
+ goto out;
}
- return 0;
+ /* And re-claim any interfaces which were claimed before the reset */
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if (handle->claimed_interfaces & (1L << i)) {
+ r = op_claim_interface(handle, i);
+ if (r) {
+ usbi_warn(HANDLE_CTX(handle),
+ "failed to re-claim interface %d after reset", i);
+ handle->claimed_interfaces &= ~(1L << i);
+ }
+ }
+ }
+out:
+ usbi_mutex_unlock(&handle->lock);
+ return ret;
}
static int op_kernel_driver_active(struct libusb_device_handle *handle,
@@ -1477,6 +1572,9 @@ static int discard_urbs(struct usbi_transfer *itransfer, int first, int last_plu
if (EINVAL == errno) {
usbi_dbg("URB not found --> assuming ready to be reaped");
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);
@@ -2136,6 +2234,7 @@ static int handle_control_completion(struct usbi_transfer *itransfer,
status = LIBUSB_TRANSFER_COMPLETED;
break;
case -ENOENT: /* cancelled */
+ status = LIBUSB_TRANSFER_CANCELLED;
break;
case -ESHUTDOWN:
usbi_dbg("device removed");
diff --git a/libusb/os/poll_windows.c b/libusb/os/poll_windows.c
index 9d6cea1..9d6f3e6 100644
--- a/libusb/os/poll_windows.c
+++ b/libusb/os/poll_windows.c
@@ -120,7 +120,7 @@ static volatile LONG compat_spinlock = 0;
// platform headers, we hook into the Kernel32 system DLL directly to seek it.
static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
#define CancelIoEx_Available (pCancelIoEx != NULL)
-__inline BOOL cancel_io(int _index)
+static __inline BOOL cancel_io(int _index)
{
if ((_index < 0) || (_index >= MAX_FDS)) {
return FALSE;
diff --git a/libusb/os/threads_posix.c b/libusb/os/threads_posix.c
new file mode 100644
index 0000000..9b8487c
--- /dev/null
+++ b/libusb/os/threads_posix.c
@@ -0,0 +1,55 @@
+/*
+ * libusb synchronization using POSIX Threads
+ *
+ * Copyright (C) 2011 Vitali Lovich <vlovich@aliph.com>
+ * Copyright (C) 2011 Peter Stuge <peter@stuge.se>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef _XOPEN_SOURCE
+# if _XOPEN_SOURCE < 500
+# undef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 500
+# endif
+#else
+#define _XOPEN_SOURCE 500
+#endif /* _XOPEN_SOURCE */
+
+#include <pthread.h>
+
+int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
+{
+ int err;
+ pthread_mutexattr_t stack_attr;
+ if (!attr) {
+ attr = &stack_attr;
+ err = pthread_mutexattr_init(&stack_attr);
+ if (err != 0)
+ return err;
+ }
+
+ err = pthread_mutexattr_settype(attr, PTHREAD_MUTEX_RECURSIVE);
+ if (err != 0)
+ goto finish;
+
+ err = pthread_mutex_init(mutex, attr);
+
+finish:
+ if (attr == &stack_attr)
+ pthread_mutexattr_destroy(&stack_attr);
+
+ return err;
+} \ No newline at end of file
diff --git a/libusb/os/threads_posix.h b/libusb/os/threads_posix.h
index dc558d4..6aa13f5 100644
--- a/libusb/os/threads_posix.h
+++ b/libusb/os/threads_posix.h
@@ -43,4 +43,6 @@
#define usbi_cond_destroy pthread_cond_destroy
#define usbi_cond_signal pthread_cond_signal
+extern int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
+
#endif /* __LIBUSB_THREADS_POSIX_H__ */
diff --git a/libusb/os/threads_windows.h b/libusb/os/threads_windows.h
index 2cd1867..9f77598 100644
--- a/libusb/os/threads_windows.h
+++ b/libusb/os/threads_windows.h
@@ -58,6 +58,8 @@ struct timespec {
#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);
@@ -81,4 +83,3 @@ int usbi_cond_broadcast(usbi_cond_t *cond);
int usbi_cond_signal(usbi_cond_t *cond);
#endif /* __LIBUSB_THREADS_WINDOWS_H__ */
-
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index 9bd6924..743632a 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -1154,7 +1154,7 @@ static int init_device(struct libusb_device* dev, struct libusb_device* parent_d
{
HANDLE handle;
DWORD size;
- USB_NODE_CONNECTION_INFORMATION conn_info;
+ 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;
@@ -1206,9 +1206,9 @@ static int init_device(struct libusb_device* dev, struct libusb_device* parent_d
usbi_warn(ctx, "could not open hub %s: %s", parent_priv->path, windows_error_str(0));
return LIBUSB_ERROR_ACCESS;
}
- size = sizeof(USB_NODE_CONNECTION_INFORMATION);
+ size = sizeof(conn_info);
conn_info.ConnectionIndex = (ULONG)port_number;
- if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, &conn_info, size,
+ 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));
@@ -1221,6 +1221,14 @@ static int init_device(struct libusb_device* dev, struct libusb_device* parent_d
return LIBUSB_ERROR_NO_DEVICE;
}
dev->device_address = (uint8_t)conn_info.DeviceAddress;
+ switch (conn_info.Speed) {
+ case 0: dev->speed = LIBUSB_SPEED_LOW; break;
+ case 1: dev->speed = LIBUSB_SPEED_FULL; break;
+ case 2: dev->speed = LIBUSB_SPEED_HIGH; break;
+ default:
+ usbi_warn(ctx, "Got unknown device speed %d", conn_info.Speed);
+ break;
+ }
memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR));
dev->num_configurations = priv->dev_descriptor.bNumConfigurations;
priv->active_config = conn_info.CurrentConfigurationValue;
diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h
index ce755e1..0abac3b 100644
--- a/libusb/os/windows_usb.h
+++ b/libusb/os/windows_usb.h
@@ -70,7 +70,7 @@ extern char *_strdup(const char *strSource);
#define safe_sprintf _snprintf
#define safe_unref_device(dev) do {if (dev != NULL) {libusb_unref_device(dev); dev = NULL;}} while(0)
#define wchar_to_utf8_ms(wstr, str, strlen) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, strlen, NULL, NULL)
-inline void upperize(char* str) {
+static inline void upperize(char* str) {
size_t i;
if (str == NULL) return;
for (i=0; i<safe_strlen(str); i++)
@@ -327,10 +327,12 @@ typedef RETURN_TYPE CONFIGRET;
#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME
#define USB_GET_NODE_INFORMATION 258
-#define USB_GET_NODE_CONNECTION_INFORMATION 259
#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260
#define USB_GET_NODE_CONNECTION_NAME 261
#define USB_GET_HUB_CAPABILITIES 271
+#if !defined(USB_GET_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
@@ -391,8 +393,8 @@ DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG)
#define IOCTL_USB_GET_NODE_INFORMATION \
CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS)
-#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION \
- CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_USB_GET_NODE_CONNECTION_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)
@@ -522,17 +524,17 @@ typedef struct _USB_PIPE_INFO {
ULONG ScheduleOffset;
} USB_PIPE_INFO, *PUSB_PIPE_INFO;
-typedef struct _USB_NODE_CONNECTION_INFORMATION {
+typedef struct _USB_NODE_CONNECTION_INFORMATION_EX {
ULONG ConnectionIndex;
USB_DEVICE_DESCRIPTOR DeviceDescriptor;
UCHAR CurrentConfigurationValue;
- BOOLEAN LowSpeed;
+ UCHAR Speed;
BOOLEAN DeviceIsHub;
USHORT DeviceAddress;
ULONG NumberOfOpenPipes;
USB_CONNECTION_STATUS ConnectionStatus;
// USB_PIPE_INFO PipeList[0];
-} USB_NODE_CONNECTION_INFORMATION, *PUSB_NODE_CONNECTION_INFORMATION;
+} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX;
typedef struct _USB_HUB_CAP_FLAGS {
ULONG HubIsHighSpeedCapable:1;