mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Upgrade libusbp.
This commit is contained in:
		| @@ -1,4 +1,4 @@ | |||||||
| cmake_minimum_required (VERSION 2.8.11) | cmake_minimum_required (VERSION 3.10.0) | ||||||
|  |  | ||||||
| # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS. | # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS. | ||||||
| if (POLICY CMP0025) | if (POLICY CMP0025) | ||||||
| @@ -18,7 +18,7 @@ endif () | |||||||
| project (libusbp) | project (libusbp) | ||||||
|  |  | ||||||
| set (LIBUSBP_VERSION_MAJOR 1) | set (LIBUSBP_VERSION_MAJOR 1) | ||||||
| set (LIBUSBP_VERSION_MINOR 2) | set (LIBUSBP_VERSION_MINOR 3) | ||||||
| set (LIBUSBP_VERSION_PATCH 0) | set (LIBUSBP_VERSION_PATCH 0) | ||||||
|  |  | ||||||
| # Make 'Release' be the default build type, since the debug builds | # Make 'Release' be the default build type, since the debug builds | ||||||
| @@ -49,28 +49,8 @@ set(VBOX_LINUX_ON_WINDOWS FALSE CACHE BOOL | |||||||
| set(ENABLE_GCOV FALSE CACHE BOOL | set(ENABLE_GCOV FALSE CACHE BOOL | ||||||
|   "Compile with special options needed for gcov.") |   "Compile with special options needed for gcov.") | ||||||
|  |  | ||||||
| # Our C code uses features from the C99 standard. | set (CMAKE_C_STANDARD 99) | ||||||
| macro(use_c99) | set (CMAKE_CXX_STANDARD 11) | ||||||
|   if (CMAKE_VERSION VERSION_LESS "3.1") |  | ||||||
|     if (CMAKE_C_COMPILER_ID STREQUAL "GNU") |  | ||||||
|       set (CMAKE_C_FLAGS "--std=gnu99 ${CMAKE_C_FLAGS}") |  | ||||||
|     endif () |  | ||||||
|   else () |  | ||||||
|     set (CMAKE_C_STANDARD 99) |  | ||||||
|   endif () |  | ||||||
| endmacro(use_c99) |  | ||||||
|  |  | ||||||
| # Our C++ code uses features from the C++11 standard. |  | ||||||
| macro(use_cxx11) |  | ||||||
|   if (CMAKE_VERSION VERSION_LESS "3.1") |  | ||||||
|     if (CMAKE_C_COMPILER_ID STREQUAL "GNU") |  | ||||||
|       # Use --std=gnu++0x instead of --std=gnu++11 in order to support GCC 4.6. |  | ||||||
|       set (CMAKE_CXX_FLAGS "--std=gnu++0x ${CMAKE_C_FLAGS}") |  | ||||||
|     endif () |  | ||||||
|   else () |  | ||||||
|     set (CMAKE_CXX_STANDARD 11) |  | ||||||
|   endif () |  | ||||||
| endmacro(use_cxx11) |  | ||||||
|  |  | ||||||
| set (LIBUSBP_VERSION ${LIBUSBP_VERSION_MAJOR}.${LIBUSBP_VERSION_MINOR}.${LIBUSBP_VERSION_PATCH}) | set (LIBUSBP_VERSION ${LIBUSBP_VERSION_MAJOR}.${LIBUSBP_VERSION_MINOR}.${LIBUSBP_VERSION_PATCH}) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,5 @@ | |||||||
| # libusbp: Pololu USB Library | # libusbp: Pololu USB Library | ||||||
|  |  | ||||||
| Version: 1.2.0<br/> |  | ||||||
| Release date: 2020-11-16<br/> |  | ||||||
| [www.pololu.com](https://www.pololu.com/) | [www.pololu.com](https://www.pololu.com/) | ||||||
|  |  | ||||||
| The **Pololu USB Library** (also known as **libusbp**) is a cross-platform C library for accessing USB devices. | The **Pololu USB Library** (also known as **libusbp**) is a cross-platform C library for accessing USB devices. | ||||||
| @@ -17,7 +15,7 @@ The **Pololu USB Library** (also known as **libusbp**) is a cross-platform C lib | |||||||
| - Provides detailed error information to the caller. | - Provides detailed error information to the caller. | ||||||
|   - Each error includes one or more English sentences describing the error, including error codes from underlying APIs. |   - Each error includes one or more English sentences describing the error, including error codes from underlying APIs. | ||||||
|   - Some errors have libusbp-defined error codes that can be used to programmatically decide how to handle the error. |   - Some errors have libusbp-defined error codes that can be used to programmatically decide how to handle the error. | ||||||
| - Provides an object-oriented C++ wrapper (using features of C++11). | - Provides an object-oriented C++ wrapper. | ||||||
| - Provides access to underlying identifiers, handles, and file descriptors. | - Provides access to underlying identifiers, handles, and file descriptors. | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -139,9 +137,9 @@ If you are using GCC and a shell that supports Bash-like syntax, here is an exam | |||||||
|  |  | ||||||
|     gcc program.c `pkg-config --cflags --libs libusbp-1` |     gcc program.c `pkg-config --cflags --libs libusbp-1` | ||||||
|  |  | ||||||
| Here is an equivalent command for C++.  Note that we use the `--std=gnu++11` option because the libusbp C++ API requires features from C++11: | Here is an equivalent command for C++: | ||||||
|  |  | ||||||
|     g++ --std=gnu++11 program.cpp `pkg-config --cflags --libs libusbp-1` |     g++ program.cpp `pkg-config --cflags --libs libusbp-1` | ||||||
|  |  | ||||||
| The order of the arguments above matters: the user program must come before libusbp because it relies on symbols that are defined by libusbp. | The order of the arguments above matters: the user program must come before libusbp because it relies on symbols that are defined by libusbp. | ||||||
|  |  | ||||||
| @@ -167,6 +165,9 @@ For detailed documentation of this library, see the header files `libusb.h` and | |||||||
|  |  | ||||||
| ## Version history | ## Version history | ||||||
|  |  | ||||||
|  | * 1.3.0 (2023-01-02): | ||||||
|  |   * Windows: Added support for detecting FTDI serial ports.  (FTDI devices with more than one port have not been tested and the interface for detecting them might change in the future.) | ||||||
|  |   * macOS: Fixed the detection of serial ports for devices that are not CDC ACM. | ||||||
| * 1.2.0 (2020-11-16): | * 1.2.0 (2020-11-16): | ||||||
|   * Linux: Made the library work with devices attached to the cp210x driver. |   * Linux: Made the library work with devices attached to the cp210x driver. | ||||||
|   * Windows: Made the library work with devices that have lowercase letters in their hardware IDs. |   * Windows: Made the library work with devices that have lowercase letters in their hardware IDs. | ||||||
|   | |||||||
| @@ -1,2 +1,3 @@ | |||||||
| This was taken from https://github.com/pololu/libusbp on 2021-12-11. | This is version 1.3.0 taken from https://github.com/pololu/libusbp on | ||||||
|  | 2023-05-06. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,3 @@ | |||||||
| use_cxx11() |  | ||||||
|  |  | ||||||
| add_executable(async_in async_in.cpp) | add_executable(async_in async_in.cpp) | ||||||
|  |  | ||||||
| include_directories ( | include_directories ( | ||||||
|   | |||||||
| @@ -1,5 +1,3 @@ | |||||||
| use_cxx11() |  | ||||||
|  |  | ||||||
| add_executable(lsport lsport.cpp) | add_executable(lsport lsport.cpp) | ||||||
|  |  | ||||||
| include_directories ( | include_directories ( | ||||||
|   | |||||||
| @@ -1,5 +1,3 @@ | |||||||
| use_cxx11() |  | ||||||
|  |  | ||||||
| add_executable(lsusb lsusb.cpp) | add_executable(lsusb lsusb.cpp) | ||||||
|  |  | ||||||
| include_directories ( | include_directories ( | ||||||
|   | |||||||
| @@ -1,5 +1,3 @@ | |||||||
| use_cxx11() |  | ||||||
|  |  | ||||||
| add_executable(port_name port_name.cpp) | add_executable(port_name port_name.cpp) | ||||||
|  |  | ||||||
| include_directories ( | include_directories ( | ||||||
|   | |||||||
| @@ -41,7 +41,6 @@ extern "C" { | |||||||
| #ifdef LIBUSBP_STATIC | #ifdef LIBUSBP_STATIC | ||||||
| #  define LIBUSBP_API | #  define LIBUSBP_API | ||||||
| #else | #else | ||||||
| #error not static |  | ||||||
| #  ifdef LIBUSBP_EXPORTS | #  ifdef LIBUSBP_EXPORTS | ||||||
| #    define LIBUSBP_API LIBUSBP_DLL_EXPORT | #    define LIBUSBP_API LIBUSBP_DLL_EXPORT | ||||||
| #  else | #  else | ||||||
|   | |||||||
| @@ -107,7 +107,7 @@ namespace libusbp | |||||||
|     { |     { | ||||||
|     public: |     public: | ||||||
|         /*! Constructor that takes a pointer. */ |         /*! Constructor that takes a pointer. */ | ||||||
|         explicit unique_pointer_wrapper(T * p = nullptr) noexcept |         explicit unique_pointer_wrapper(T * p = NULL) noexcept | ||||||
|             : pointer(p) |             : pointer(p) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
| @@ -133,9 +133,9 @@ namespace libusbp | |||||||
|  |  | ||||||
|         /*! Implicit conversion to bool.  Returns true if the underlying pointer |         /*! Implicit conversion to bool.  Returns true if the underlying pointer | ||||||
|          *  is not NULL. */ |          *  is not NULL. */ | ||||||
|         explicit operator bool() const noexcept |         operator bool() const noexcept | ||||||
|         { |         { | ||||||
|             return pointer != nullptr; |             return pointer != NULL; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /*! Returns the underlying pointer. */ |         /*! Returns the underlying pointer. */ | ||||||
| @@ -146,19 +146,19 @@ namespace libusbp | |||||||
|  |  | ||||||
|         /*! Sets the underlying pointer to the specified value, freeing the |         /*! Sets the underlying pointer to the specified value, freeing the | ||||||
|          * previous pointer and taking ownership of the specified one. */ |          * previous pointer and taking ownership of the specified one. */ | ||||||
|         void pointer_reset(T * p = nullptr) noexcept |         void pointer_reset(T * p = NULL) noexcept | ||||||
|         { |         { | ||||||
|             pointer_free(pointer); |             pointer_free(pointer); | ||||||
|             pointer = p; |             pointer = p; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /*! Releases the pointer, transferring ownership of it to the caller and |         /*! Releases the pointer, transferring ownership of it to the caller and | ||||||
|          * resetting the underlying pointer of this object to nullptr.  The caller |          * resetting the underlying pointer of this object to NULL.  The caller | ||||||
|          * is responsible for freeing the returned pointer if it is not NULL. */ |          * is responsible for freeing the returned pointer if it is not NULL. */ | ||||||
|         T * pointer_release() noexcept |         T * pointer_release() noexcept | ||||||
|         { |         { | ||||||
|             T * p = pointer; |             T * p = pointer; | ||||||
|             pointer = nullptr; |             pointer = NULL; | ||||||
|             return p; |             return p; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -193,14 +193,14 @@ namespace libusbp | |||||||
|     { |     { | ||||||
|     public: |     public: | ||||||
|         /*! Constructor that takes a pointer. */ |         /*! Constructor that takes a pointer. */ | ||||||
|         explicit unique_pointer_wrapper_with_copy(T * p = nullptr) noexcept |         explicit unique_pointer_wrapper_with_copy(T * p = NULL) noexcept | ||||||
|             : unique_pointer_wrapper<T>(p) |             : unique_pointer_wrapper<T>(p) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /*! Move constructor. */ |         /*! Move constructor. */ | ||||||
|         unique_pointer_wrapper_with_copy( |         unique_pointer_wrapper_with_copy( | ||||||
|             unique_pointer_wrapper_with_copy && other) noexcept = default; |             unique_pointer_wrapper_with_copy && other) = default; | ||||||
|  |  | ||||||
|         /*! Copy constructor */ |         /*! Copy constructor */ | ||||||
|         unique_pointer_wrapper_with_copy( |         unique_pointer_wrapper_with_copy( | ||||||
| @@ -228,13 +228,14 @@ namespace libusbp | |||||||
|     { |     { | ||||||
|     public: |     public: | ||||||
|         /*! Constructor that takes a pointer.  */ |         /*! Constructor that takes a pointer.  */ | ||||||
|         explicit error(libusbp_error * p = nullptr) noexcept |         explicit error(libusbp_error * p = NULL) noexcept | ||||||
|             : unique_pointer_wrapper_with_copy(p) |             : unique_pointer_wrapper_with_copy(p) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /*! Wrapper for libusbp_error_get_message(). */ |         /*! Wrapper for libusbp_error_get_message(). */ | ||||||
|         const char * what() const noexcept override { |         virtual const char * what() const noexcept | ||||||
|  |         { | ||||||
|             return libusbp_error_get_message(pointer); |             return libusbp_error_get_message(pointer); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -255,7 +256,7 @@ namespace libusbp | |||||||
|     /*! \cond */ |     /*! \cond */ | ||||||
|     inline void throw_if_needed(libusbp_error * err) |     inline void throw_if_needed(libusbp_error * err) | ||||||
|     { |     { | ||||||
|         if (err != nullptr) |         if (err != NULL) | ||||||
|         { |         { | ||||||
|             throw error(err); |             throw error(err); | ||||||
|         } |         } | ||||||
| @@ -267,7 +268,7 @@ namespace libusbp | |||||||
|     { |     { | ||||||
|     public: |     public: | ||||||
|         /*! Constructor that takes a pointer. */ |         /*! Constructor that takes a pointer. */ | ||||||
|         explicit async_in_pipe(libusbp_async_in_pipe * pointer = nullptr) |         explicit async_in_pipe(libusbp_async_in_pipe * pointer = NULL) | ||||||
|             : unique_pointer_wrapper(pointer) |             : unique_pointer_wrapper(pointer) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
| @@ -303,8 +304,8 @@ namespace libusbp | |||||||
|         bool handle_finished_transfer(void * buffer, size_t * transferred, |         bool handle_finished_transfer(void * buffer, size_t * transferred, | ||||||
|             error * transfer_error) |             error * transfer_error) | ||||||
|         { |         { | ||||||
|             libusbp_error ** error_out = nullptr; |             libusbp_error ** error_out = NULL; | ||||||
|             if (transfer_error != nullptr) |             if (transfer_error != NULL) | ||||||
|             { |             { | ||||||
|                 transfer_error->pointer_reset(); |                 transfer_error->pointer_reset(); | ||||||
|                 error_out = transfer_error->pointer_to_pointer_get(); |                 error_out = transfer_error->pointer_to_pointer_get(); | ||||||
| @@ -328,7 +329,7 @@ namespace libusbp | |||||||
|     { |     { | ||||||
|     public: |     public: | ||||||
|         /*! Constructor that takes a pointer. */ |         /*! Constructor that takes a pointer. */ | ||||||
|         explicit device(libusbp_device * pointer = nullptr) : |         explicit device(libusbp_device * pointer = NULL) : | ||||||
|             unique_pointer_wrapper_with_copy(pointer) |             unique_pointer_wrapper_with_copy(pointer) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
| @@ -387,7 +388,7 @@ namespace libusbp | |||||||
|         std::vector<device> vector; |         std::vector<device> vector; | ||||||
|         for(size_t i = 0; i < size; i++) |         for(size_t i = 0; i < size; i++) | ||||||
|         { |         { | ||||||
|             vector.emplace_back(device_list[i]); |             vector.push_back(device(device_list[i])); | ||||||
|         } |         } | ||||||
|         libusbp_list_free(device_list); |         libusbp_list_free(device_list); | ||||||
|         return vector; |         return vector; | ||||||
| @@ -408,13 +409,13 @@ namespace libusbp | |||||||
|     public: |     public: | ||||||
|         /*! Constructor that takes a pointer.  This object will free the pointer |         /*! Constructor that takes a pointer.  This object will free the pointer | ||||||
|          *  when it is destroyed. */ |          *  when it is destroyed. */ | ||||||
|         explicit generic_interface(libusbp_generic_interface * pointer = nullptr) |         explicit generic_interface(libusbp_generic_interface * pointer = NULL) | ||||||
|             : unique_pointer_wrapper_with_copy(pointer) |             : unique_pointer_wrapper_with_copy(pointer) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /*! Wrapper for libusbp_generic_interface_create. */ |         /*! Wrapper for libusbp_generic_interface_create. */ | ||||||
|         explicit generic_interface(const device & device, |         generic_interface(const device & device, | ||||||
|             uint8_t interface_number = 0, bool composite = false) |             uint8_t interface_number = 0, bool composite = false) | ||||||
|         { |         { | ||||||
|             throw_if_needed(libusbp_generic_interface_create( |             throw_if_needed(libusbp_generic_interface_create( | ||||||
| @@ -448,13 +449,13 @@ namespace libusbp | |||||||
|     public: |     public: | ||||||
|         /*! Constructor that takes a pointer.  This object will free the pointer |         /*! Constructor that takes a pointer.  This object will free the pointer | ||||||
|          *  when it is destroyed. */ |          *  when it is destroyed. */ | ||||||
|         explicit generic_handle(libusbp_generic_handle * pointer = nullptr) noexcept |         explicit generic_handle(libusbp_generic_handle * pointer = NULL) noexcept | ||||||
|             : unique_pointer_wrapper(pointer) |             : unique_pointer_wrapper(pointer) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /*! Wrapper for libusbp_generic_handle_open(). */ |         /*! Wrapper for libusbp_generic_handle_open(). */ | ||||||
|         explicit generic_handle(const generic_interface & gi) |         generic_handle(const generic_interface & gi) | ||||||
|         { |         { | ||||||
|             throw_if_needed(libusbp_generic_handle_open(gi.pointer_get(), &pointer)); |             throw_if_needed(libusbp_generic_handle_open(gi.pointer_get(), &pointer)); | ||||||
|         } |         } | ||||||
| @@ -486,9 +487,9 @@ namespace libusbp | |||||||
|             uint8_t bRequest, |             uint8_t bRequest, | ||||||
|             uint16_t wValue, |             uint16_t wValue, | ||||||
|             uint16_t wIndex, |             uint16_t wIndex, | ||||||
|             void * buffer = nullptr, |             void * buffer = NULL, | ||||||
|             uint16_t wLength = 0, |             uint16_t wLength = 0, | ||||||
|             size_t * transferred = nullptr) |             size_t * transferred = NULL) | ||||||
|         { |         { | ||||||
|             throw_if_needed(libusbp_control_transfer(pointer, |             throw_if_needed(libusbp_control_transfer(pointer, | ||||||
|                 bmRequestType, bRequest, wValue, wIndex, |                 bmRequestType, bRequest, wValue, wIndex, | ||||||
| @@ -542,13 +543,13 @@ namespace libusbp | |||||||
|     public: |     public: | ||||||
|         /*! Constructor that takes a pointer.  This object will free the pointer |         /*! Constructor that takes a pointer.  This object will free the pointer | ||||||
|          *  when it is destroyed. */ |          *  when it is destroyed. */ | ||||||
|         explicit serial_port(libusbp_serial_port * pointer = nullptr) |         explicit serial_port(libusbp_serial_port * pointer = NULL) | ||||||
|             : unique_pointer_wrapper_with_copy(pointer) |             : unique_pointer_wrapper_with_copy(pointer) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /*! Wrapper for libusbp_serial_port_create(). */ |         /*! Wrapper for libusbp_serial_port_create(). */ | ||||||
|         explicit serial_port(const device & device, |         serial_port(const device & device, | ||||||
|             uint8_t interface_number = 0, bool composite = false) |             uint8_t interface_number = 0, bool composite = false) | ||||||
|         { |         { | ||||||
|             throw_if_needed(libusbp_serial_port_create( |             throw_if_needed(libusbp_serial_port_create( | ||||||
|   | |||||||
| @@ -1,5 +1,3 @@ | |||||||
| use_c99() |  | ||||||
|  |  | ||||||
| add_library (install_helper SHARED install_helper_windows.c dll.def) | add_library (install_helper SHARED install_helper_windows.c dll.def) | ||||||
|  |  | ||||||
| target_link_libraries (install_helper setupapi msi) | target_link_libraries (install_helper setupapi msi) | ||||||
|   | |||||||
| @@ -1,5 +1,3 @@ | |||||||
| use_cxx11() |  | ||||||
|  |  | ||||||
| add_executable(test_async_in test_async_in.cpp) | add_executable(test_async_in test_async_in.cpp) | ||||||
|  |  | ||||||
| include_directories ( | include_directories ( | ||||||
|   | |||||||
| @@ -1,5 +1,3 @@ | |||||||
| use_cxx11() |  | ||||||
|  |  | ||||||
| add_executable(test_long_read test_long_read.cpp) | add_executable(test_long_read test_long_read.cpp) | ||||||
|  |  | ||||||
| include_directories ( | include_directories ( | ||||||
|   | |||||||
| @@ -1,5 +1,3 @@ | |||||||
| use_cxx11() |  | ||||||
|  |  | ||||||
| add_executable(test_long_write test_long_write.cpp) | add_executable(test_long_write test_long_write.cpp) | ||||||
|  |  | ||||||
| include_directories ( | include_directories ( | ||||||
|   | |||||||
| @@ -1,5 +1,3 @@ | |||||||
| use_cxx11() |  | ||||||
|  |  | ||||||
| add_executable(test_transitions test_transitions.cpp) | add_executable(test_transitions test_transitions.cpp) | ||||||
|  |  | ||||||
| include_directories ( | include_directories ( | ||||||
|   | |||||||
| @@ -1,5 +1,3 @@ | |||||||
| use_c99() |  | ||||||
|  |  | ||||||
| # Settings for GCC | # Settings for GCC | ||||||
| if (CMAKE_C_COMPILER_ID STREQUAL "GNU") | if (CMAKE_C_COMPILER_ID STREQUAL "GNU") | ||||||
|   # By default, symbols are not visible outside of the library. |   # By default, symbols are not visible outside of the library. | ||||||
|   | |||||||
| @@ -124,7 +124,7 @@ libusbp_error * error_add_v(libusbp_error * error, const char * format, va_list | |||||||
|         int result = vsnprintf(x, 0, format, ap2); |         int result = vsnprintf(x, 0, format, ap2); | ||||||
|         if (result > 0) |         if (result > 0) | ||||||
|         { |         { | ||||||
|             outer_message_length = (size_t) result; |             outer_message_length = result; | ||||||
|         } |         } | ||||||
|         va_end(ap2); |         va_end(ap2); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -37,7 +37,10 @@ libusbp_error * libusbp_find_device_with_vid_pid( | |||||||
|  |  | ||||||
|     libusbp_device ** new_list = NULL; |     libusbp_device ** new_list = NULL; | ||||||
|     size_t size = 0; |     size_t size = 0; | ||||||
|     error = libusbp_list_connected_devices(&new_list, &size); |     if (error == NULL) | ||||||
|  |     { | ||||||
|  |         error = libusbp_list_connected_devices(&new_list, &size); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     assert(error != NULL || new_list != NULL); |     assert(error != NULL || new_list != NULL); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -37,6 +37,7 @@ | |||||||
| #include <usbioctl.h> | #include <usbioctl.h> | ||||||
| #include <stringapiset.h> | #include <stringapiset.h> | ||||||
| #include <winusb.h> | #include <winusb.h> | ||||||
|  | #include <ntddmodm.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef __linux__ | #ifdef __linux__ | ||||||
|   | |||||||
| @@ -51,11 +51,14 @@ libusbp_error * async_in_transfer_create( | |||||||
|     libusbp_error * error = NULL; |     libusbp_error * error = NULL; | ||||||
|  |  | ||||||
|     // Allocate memory for the transfer struct. |     // Allocate memory for the transfer struct. | ||||||
|     async_in_transfer * new_transfer = calloc(1, sizeof(async_in_transfer)); |     async_in_transfer * new_transfer = NULL; | ||||||
|  |     if (error == NULL) | ||||||
|     if (new_transfer == NULL) |  | ||||||
|     { |     { | ||||||
|         error = &error_no_memory; |         new_transfer = calloc(1, sizeof(async_in_transfer)); | ||||||
|  |         if (new_transfer == NULL) | ||||||
|  |         { | ||||||
|  |             error = &error_no_memory; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Allocate memory for the buffer. |     // Allocate memory for the buffer. | ||||||
|   | |||||||
| @@ -25,9 +25,14 @@ libusbp_error * create_device(io_service_t service, libusbp_device ** device) | |||||||
|     assert(service != MACH_PORT_NULL); |     assert(service != MACH_PORT_NULL); | ||||||
|     assert(device != NULL); |     assert(device != NULL); | ||||||
|  |  | ||||||
|  |     libusbp_error * error = NULL; | ||||||
|  |  | ||||||
|     // Allocate the device. |     // Allocate the device. | ||||||
|     libusbp_device * new_device = NULL; |     libusbp_device * new_device = NULL; | ||||||
|     libusbp_error * error = device_allocate(&new_device); |     if (error == NULL) | ||||||
|  |     { | ||||||
|  |         error = device_allocate(&new_device); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Get the numeric IDs. |     // Get the numeric IDs. | ||||||
|     if (error == NULL) |     if (error == NULL) | ||||||
| @@ -84,7 +89,10 @@ libusbp_error * libusbp_device_copy(const libusbp_device * source, libusbp_devic | |||||||
|  |  | ||||||
|     // Allocate the device. |     // Allocate the device. | ||||||
|     libusbp_device * new_device = NULL; |     libusbp_device * new_device = NULL; | ||||||
|     error = device_allocate(&new_device); |     if (error == NULL) | ||||||
|  |     { | ||||||
|  |         error = device_allocate(&new_device); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Copy the simple fields, while leaving the pointers owned by the |     // Copy the simple fields, while leaving the pointers owned by the | ||||||
|     // device NULL so that libusbp_device_free is still OK to call. |     // device NULL so that libusbp_device_free is still OK to call. | ||||||
|   | |||||||
| @@ -63,9 +63,8 @@ static libusbp_error * process_pipe_properties(libusbp_generic_handle * handle) | |||||||
|         uint8_t transfer_type; |         uint8_t transfer_type; | ||||||
|         uint16_t max_packet_size; |         uint16_t max_packet_size; | ||||||
|         uint8_t interval; |         uint8_t interval; | ||||||
|         kr = (*handle->ioh)->GetPipeProperties(handle->ioh, (UInt8) i, |         kern_return_t kr = (*handle->ioh)->GetPipeProperties(handle->ioh, i, | ||||||
|           &direction, &endpoint_number, &transfer_type, &max_packet_size, &interval); |             &direction, &endpoint_number, &transfer_type, &max_packet_size, &interval); | ||||||
|  |  | ||||||
|         if (kr != KERN_SUCCESS) |         if (kr != KERN_SUCCESS) | ||||||
|         { |         { | ||||||
|             return error_create_mach(kr, "Failed to get pipe properties for pipe %d.", i); |             return error_create_mach(kr, "Failed to get pipe properties for pipe %d.", i); | ||||||
| @@ -75,11 +74,11 @@ static libusbp_error * process_pipe_properties(libusbp_generic_handle * handle) | |||||||
|         { |         { | ||||||
|             if (direction) |             if (direction) | ||||||
|             { |             { | ||||||
|                 handle->in_pipe_index[endpoint_number] = (uint8_t) i; |                 handle->in_pipe_index[endpoint_number] = i; | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                 handle->out_pipe_index[endpoint_number] = (uint8_t) i; |                 handle->out_pipe_index[endpoint_number] = i; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -96,11 +95,14 @@ static libusbp_error * set_configuration(io_service_t service) | |||||||
|     // Turn io_service_t into something we can actually use. |     // Turn io_service_t into something we can actually use. | ||||||
|     IOUSBDeviceInterface ** dev_handle = NULL; |     IOUSBDeviceInterface ** dev_handle = NULL; | ||||||
|     IOCFPlugInInterface ** plug_in = NULL; |     IOCFPlugInInterface ** plug_in = NULL; | ||||||
|     error = service_to_interface(service, |     if (error == NULL) | ||||||
|         kIOUSBDeviceUserClientTypeID, |     { | ||||||
|         CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID197), |         error = service_to_interface(service, | ||||||
|         (void **)&dev_handle, |             kIOUSBDeviceUserClientTypeID, | ||||||
|         &plug_in); |             CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID197), | ||||||
|  |             (void **)&dev_handle, | ||||||
|  |             &plug_in); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     uint8_t config_num = 0; |     uint8_t config_num = 0; | ||||||
|     if (error == NULL) |     if (error == NULL) | ||||||
| @@ -170,7 +172,10 @@ static libusbp_error * set_configuration_and_get_service( | |||||||
|  |  | ||||||
|     // Get an io_service_t for the physical device. |     // Get an io_service_t for the physical device. | ||||||
|     io_service_t device_service = MACH_PORT_NULL; |     io_service_t device_service = MACH_PORT_NULL; | ||||||
|     error = service_get_from_id(device_id, &device_service); |     if (error == NULL) | ||||||
|  |     { | ||||||
|  |         error = service_get_from_id(device_id, &device_service); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Set the configruation to 1 if it is not set. |     // Set the configruation to 1 if it is not set. | ||||||
|     if (error == NULL) |     if (error == NULL) | ||||||
| @@ -209,11 +214,13 @@ libusbp_error * libusbp_generic_handle_open( | |||||||
|  |  | ||||||
|     // Allocate memory for the handle. |     // Allocate memory for the handle. | ||||||
|     libusbp_generic_handle * new_handle = NULL; |     libusbp_generic_handle * new_handle = NULL; | ||||||
|     new_handle = calloc(1, sizeof(libusbp_generic_handle)); |     if (error == NULL) | ||||||
|  |  | ||||||
|     if (new_handle == NULL) |  | ||||||
|     { |     { | ||||||
|         error = &error_no_memory; |         new_handle = calloc(1, sizeof(libusbp_generic_handle)); | ||||||
|  |         if (new_handle == NULL) | ||||||
|  |         { | ||||||
|  |             error = &error_no_memory; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Get the io_service_t representing the IOUSBInterface. |     // Get the io_service_t representing the IOUSBInterface. | ||||||
| @@ -323,11 +330,14 @@ libusbp_error * libusbp_generic_handle_set_timeout( | |||||||
|  |  | ||||||
|     libusbp_error * error = NULL; |     libusbp_error * error = NULL; | ||||||
|  |  | ||||||
|     error = check_pipe_id(pipe_id); |     if (error == NULL) | ||||||
|  |     { | ||||||
|  |         error = check_pipe_id(pipe_id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (error == NULL) |     if (error == NULL) | ||||||
|     { |     { | ||||||
|         uint8_t endpoint_number = pipe_id & (uint8_t) MAX_ENDPOINT_NUMBER; |         uint8_t endpoint_number = pipe_id & MAX_ENDPOINT_NUMBER; | ||||||
|  |  | ||||||
|         if (pipe_id & 0x80) |         if (pipe_id & 0x80) | ||||||
|         { |         { | ||||||
| @@ -401,7 +411,7 @@ libusbp_error * libusbp_read_pipe( | |||||||
|  |  | ||||||
|     libusbp_error * error = NULL; |     libusbp_error * error = NULL; | ||||||
|  |  | ||||||
|     if (size == 0) |     if (error == NULL && size == 0) | ||||||
|     { |     { | ||||||
|         error = error_create("Transfer size 0 is not allowed."); |         error = error_create("Transfer size 0 is not allowed."); | ||||||
|     } |     } | ||||||
| @@ -423,12 +433,12 @@ libusbp_error * libusbp_read_pipe( | |||||||
|  |  | ||||||
|     if (error == NULL) |     if (error == NULL) | ||||||
|     { |     { | ||||||
|         uint8_t endpoint_number = pipe_id & (uint8_t) MAX_ENDPOINT_NUMBER; |         uint8_t endpoint_number = pipe_id & MAX_ENDPOINT_NUMBER; | ||||||
|         uint32_t no_data_timeout = 0; |         uint32_t no_data_timeout = 0; | ||||||
|         uint32_t completion_timeout = handle->in_timeout[endpoint_number]; |         uint32_t completion_timeout = handle->in_timeout[endpoint_number]; | ||||||
|         uint32_t iokit_size = (uint32_t) size; |         uint32_t iokit_size = size; | ||||||
|         uint32_t pipe_index = handle->in_pipe_index[endpoint_number]; |         uint32_t pipe_index = handle->in_pipe_index[endpoint_number]; | ||||||
|         kern_return_t kr = (*handle->ioh)->ReadPipeTO(handle->ioh, (UInt8) pipe_index, |         kern_return_t kr = (*handle->ioh)->ReadPipeTO(handle->ioh, pipe_index, | ||||||
|           buffer, &iokit_size, no_data_timeout, completion_timeout); |           buffer, &iokit_size, no_data_timeout, completion_timeout); | ||||||
|         if (transferred != NULL) { *transferred = iokit_size; } |         if (transferred != NULL) { *transferred = iokit_size; } | ||||||
|         if (kr != KERN_SUCCESS) |         if (kr != KERN_SUCCESS) | ||||||
| @@ -464,7 +474,7 @@ libusbp_error * libusbp_write_pipe( | |||||||
|  |  | ||||||
|     libusbp_error * error = NULL; |     libusbp_error * error = NULL; | ||||||
|  |  | ||||||
|     if (size > UINT32_MAX) |     if (error == NULL && size > UINT32_MAX) | ||||||
|     { |     { | ||||||
|         error = error_create("Transfer size is too large."); |         error = error_create("Transfer size is too large."); | ||||||
|     } |     } | ||||||
| @@ -481,12 +491,12 @@ libusbp_error * libusbp_write_pipe( | |||||||
|  |  | ||||||
|     if (error == NULL) |     if (error == NULL) | ||||||
|     { |     { | ||||||
|         uint8_t endpoint_number = pipe_id & (uint8_t) MAX_ENDPOINT_NUMBER; |         uint8_t endpoint_number = pipe_id & MAX_ENDPOINT_NUMBER; | ||||||
|         uint32_t no_data_timeout = 0; |         uint32_t no_data_timeout = 0; | ||||||
|         uint32_t completion_timeout = handle->out_timeout[endpoint_number]; |         uint32_t completion_timeout = handle->out_timeout[endpoint_number]; | ||||||
|         uint32_t pipe_index = handle->out_pipe_index[endpoint_number]; |         uint32_t pipe_index = handle->out_pipe_index[endpoint_number]; | ||||||
|         kern_return_t kr = (*handle->ioh)->WritePipeTO(handle->ioh, (UInt8) pipe_index, |         kern_return_t kr = (*handle->ioh)->WritePipeTO(handle->ioh, pipe_index, | ||||||
|           (void *)buffer, (UInt32) size, no_data_timeout, completion_timeout); |           (void *)buffer, size, no_data_timeout, completion_timeout); | ||||||
|         if (kr != KERN_SUCCESS) |         if (kr != KERN_SUCCESS) | ||||||
|         { |         { | ||||||
|             error = error_create_mach(kr, ""); |             error = error_create_mach(kr, ""); | ||||||
| @@ -588,7 +598,7 @@ IOUSBInterfaceInterface182 ** generic_handle_get_ioh(const libusbp_generic_handl | |||||||
|  |  | ||||||
| uint8_t generic_handle_get_pipe_index(const libusbp_generic_handle * handle, uint8_t pipe_id) | uint8_t generic_handle_get_pipe_index(const libusbp_generic_handle * handle, uint8_t pipe_id) | ||||||
| { | { | ||||||
|     uint8_t endpoint_number = pipe_id & (uint8_t) MAX_ENDPOINT_NUMBER; |     uint8_t endpoint_number = pipe_id & MAX_ENDPOINT_NUMBER; | ||||||
|     if (pipe_id & 0x80) |     if (pipe_id & 0x80) | ||||||
|     { |     { | ||||||
|         return handle->in_pipe_index[endpoint_number]; |         return handle->in_pipe_index[endpoint_number]; | ||||||
|   | |||||||
| @@ -82,7 +82,10 @@ libusbp_error * libusbp_generic_interface_create( | |||||||
|     { |     { | ||||||
|         // Get an io_service_t for the physical device. |         // Get an io_service_t for the physical device. | ||||||
|         io_service_t device_service = MACH_PORT_NULL; |         io_service_t device_service = MACH_PORT_NULL; | ||||||
|         error = service_get_from_id(new_gi->device_id, &device_service); |         if (error == NULL) | ||||||
|  |         { | ||||||
|  |             error = service_get_from_id(new_gi->device_id, &device_service); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // Get the io_service_t for the interface. |         // Get the io_service_t for the interface. | ||||||
|         io_service_t interface_service = MACH_PORT_NULL; |         io_service_t interface_service = MACH_PORT_NULL; | ||||||
| @@ -146,7 +149,10 @@ libusbp_error * libusbp_generic_interface_copy( | |||||||
|  |  | ||||||
|     // Allocate the generic interface. |     // Allocate the generic interface. | ||||||
|     libusbp_generic_interface * new_gi = NULL; |     libusbp_generic_interface * new_gi = NULL; | ||||||
|     error = generic_interface_allocate(&new_gi); |     if (error == NULL) | ||||||
|  |     { | ||||||
|  |         error = generic_interface_allocate(&new_gi); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Copy the simple fields. |     // Copy the simple fields. | ||||||
|     if (error == NULL) |     if (error == NULL) | ||||||
|   | |||||||
| @@ -42,12 +42,14 @@ libusbp_error * service_get_usb_interface(io_service_t service, | |||||||
|     libusbp_error * error = NULL; |     libusbp_error * error = NULL; | ||||||
|  |  | ||||||
|     io_iterator_t iterator = MACH_PORT_NULL; |     io_iterator_t iterator = MACH_PORT_NULL; | ||||||
|     kern_return_t result = IORegistryEntryGetChildIterator( |     if (error == NULL) | ||||||
|         service, kIOServicePlane, &iterator); |  | ||||||
|  |  | ||||||
|     if (result != KERN_SUCCESS) |  | ||||||
|     { |     { | ||||||
|         error = error_create_mach(result, "Failed to get child iterator."); |         kern_return_t result = IORegistryEntryGetChildIterator( | ||||||
|  |             service, kIOServicePlane, &iterator); | ||||||
|  |         if (result != KERN_SUCCESS) | ||||||
|  |         { | ||||||
|  |             error = error_create_mach(result, "Failed to get child iterator."); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Loop through the devices to find the right one. |     // Loop through the devices to find the right one. | ||||||
| @@ -57,7 +59,7 @@ libusbp_error * service_get_usb_interface(io_service_t service, | |||||||
|         if (candidate == MACH_PORT_NULL) { break; } |         if (candidate == MACH_PORT_NULL) { break; } | ||||||
|  |  | ||||||
|         // Filter out candidates that are not of class IOUSBInterface. |         // Filter out candidates that are not of class IOUSBInterface. | ||||||
|         bool conforms = (bool) IOObjectConformsTo(candidate, kIOUSBInterfaceClassName); |         bool conforms = IOObjectConformsTo(candidate, kIOUSBInterfaceClassName); | ||||||
|         if (!conforms) |         if (!conforms) | ||||||
|         { |         { | ||||||
|             IOObjectRelease(candidate); |             IOObjectRelease(candidate); | ||||||
| @@ -88,54 +90,6 @@ libusbp_error * service_get_usb_interface(io_service_t service, | |||||||
|     return error; |     return error; | ||||||
| } | } | ||||||
|  |  | ||||||
| libusbp_error * service_get_child_by_class(io_service_t service, |  | ||||||
|     const char * class_name, io_service_t * interface_service) |  | ||||||
| { |  | ||||||
|     assert(service != MACH_PORT_NULL); |  | ||||||
|     assert(interface_service != NULL); |  | ||||||
|  |  | ||||||
|     *interface_service = MACH_PORT_NULL; |  | ||||||
|  |  | ||||||
|     libusbp_error * error = NULL; |  | ||||||
|  |  | ||||||
|     io_iterator_t iterator = MACH_PORT_NULL; |  | ||||||
|     kern_return_t result = IORegistryEntryCreateIterator( |  | ||||||
|         service, kIOServicePlane, kIORegistryIterateRecursively, &iterator); |  | ||||||
|  |  | ||||||
|     if (result != KERN_SUCCESS) |  | ||||||
|     { |  | ||||||
|         error = error_create_mach(result, "Failed to get recursive iterator."); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Loop through the devices to find the right one. |  | ||||||
|     while (error == NULL) |  | ||||||
|     { |  | ||||||
|         io_service_t candidate = IOIteratorNext(iterator); |  | ||||||
|         if (candidate == MACH_PORT_NULL) { break; } |  | ||||||
|  |  | ||||||
|         // Filter out candidates that are not the right class. |  | ||||||
|         bool conforms = (bool) IOObjectConformsTo(candidate, class_name); |  | ||||||
|         if (!conforms) |  | ||||||
|         { |  | ||||||
|             IOObjectRelease(candidate); |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // This is the right one.  Pass it to the caller. |  | ||||||
|         *interface_service = candidate; |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (error == NULL && *interface_service == MACH_PORT_NULL) |  | ||||||
|     { |  | ||||||
|         error = error_create("Could not find entry with class %s.", class_name); |  | ||||||
|         error = error_add_code(error, LIBUSBP_ERROR_NOT_READY); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (iterator != MACH_PORT_NULL) { IOObjectRelease(iterator); } |  | ||||||
|     return error; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| libusbp_error * service_to_interface( | libusbp_error * service_to_interface( | ||||||
|     io_service_t service, |     io_service_t service, | ||||||
|     CFUUIDRef pluginType, |     CFUUIDRef pluginType, | ||||||
| @@ -154,13 +108,15 @@ libusbp_error * service_to_interface( | |||||||
|  |  | ||||||
|     // Create the plug-in interface. |     // Create the plug-in interface. | ||||||
|     IOCFPlugInInterface ** new_plug_in = NULL; |     IOCFPlugInInterface ** new_plug_in = NULL; | ||||||
|     kern_return_t kr = IOCreatePlugInInterfaceForService(service, |     if (error == NULL) | ||||||
|         pluginType, kIOCFPlugInInterfaceID, |  | ||||||
|         &new_plug_in, &score); |  | ||||||
|  |  | ||||||
|     if (kr != KERN_SUCCESS) |  | ||||||
|     { |     { | ||||||
|         error = error_create_mach(kr, "Failed to create plug-in interface."); |         kern_return_t kr = IOCreatePlugInInterfaceForService(service, | ||||||
|  |             pluginType, kIOCFPlugInInterfaceID, | ||||||
|  |             &new_plug_in, &score); | ||||||
|  |         if (kr != KERN_SUCCESS) | ||||||
|  |         { | ||||||
|  |             error = error_create_mach(kr, "Failed to create plug-in interface."); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Create the device interface and pass it to the caller. |     // Create the device interface and pass it to the caller. | ||||||
| @@ -223,7 +179,7 @@ libusbp_error * get_string(io_registry_entry_t entry, CFStringRef name, char ** | |||||||
|  |  | ||||||
|     libusbp_error * error = NULL; |     libusbp_error * error = NULL; | ||||||
|  |  | ||||||
|     if (CFGetTypeID(cf_value) != CFStringGetTypeID()) |     if (error == NULL && CFGetTypeID(cf_value) != CFStringGetTypeID()) | ||||||
|     { |     { | ||||||
|         error = error_create("Property is not a string."); |         error = error_create("Property is not a string."); | ||||||
|     } |     } | ||||||
| @@ -244,7 +200,7 @@ libusbp_error * get_string(io_registry_entry_t entry, CFStringRef name, char ** | |||||||
|         error = string_copy(buffer, value); |         error = string_copy(buffer, value); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     CFRelease(cf_value); |     if (cf_value != NULL) { CFRelease(cf_value); } | ||||||
|     return error; |     return error; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -258,11 +214,14 @@ libusbp_error * get_int32(io_registry_entry_t entry, CFStringRef name, int32_t * | |||||||
|  |  | ||||||
|     libusbp_error * error = NULL; |     libusbp_error * error = NULL; | ||||||
|  |  | ||||||
|     CFTypeRef cf_value = IORegistryEntryCreateCFProperty(entry, name, kCFAllocatorDefault, 0); |     CFTypeRef cf_value = NULL; | ||||||
|  |     if (error == NULL) | ||||||
|     if (cf_value == NULL) |  | ||||||
|     { |     { | ||||||
|         error = error_create("Failed to get int32 property from IORegistryEntry."); |         cf_value = IORegistryEntryCreateCFProperty(entry, name, kCFAllocatorDefault, 0); | ||||||
|  |         if (cf_value == NULL) | ||||||
|  |         { | ||||||
|  |             error = error_create("Failed to get int32 property from IORegistryEntry."); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (error == NULL && CFGetTypeID(cf_value) != CFNumberGetTypeID()) |     if (error == NULL && CFGetTypeID(cf_value) != CFNumberGetTypeID()) | ||||||
| @@ -292,13 +251,16 @@ libusbp_error * get_uint16(io_registry_entry_t entry, CFStringRef name, uint16_t | |||||||
|     libusbp_error * error = NULL; |     libusbp_error * error = NULL; | ||||||
|  |  | ||||||
|     int32_t tmp; |     int32_t tmp; | ||||||
|     error = get_int32(entry, name, &tmp); |     if (error == NULL) | ||||||
|  |     { | ||||||
|  |         error = get_int32(entry, name, &tmp); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (error == NULL) |     if (error == NULL) | ||||||
|     { |     { | ||||||
|         // There is an unchecked conversion of an int32_t to a uint16_t here but |         // There is an implicit conversion of an int32_t to a uint16_t here but | ||||||
|         // we don't expect any data to be lost. |         // we don't expect any data to be lost. | ||||||
|         *value = (uint16_t) tmp; |         *value = tmp; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return error; |     return error; | ||||||
|   | |||||||
| @@ -37,10 +37,13 @@ libusbp_error * libusbp_list_connected_devices( | |||||||
|     // Create a dictionary that says "IOProviderClass" => "IOUSBDevice" |     // Create a dictionary that says "IOProviderClass" => "IOUSBDevice" | ||||||
|     // This dictionary is CFReleased by IOServiceGetMatchingServices. |     // This dictionary is CFReleased by IOServiceGetMatchingServices. | ||||||
|     CFMutableDictionaryRef dict = NULL; |     CFMutableDictionaryRef dict = NULL; | ||||||
|     dict = IOServiceMatching("IOUSBHostDevice"); |     if (error == NULL) | ||||||
|     if (dict == NULL) |  | ||||||
|     { |     { | ||||||
|         error = error_create("IOServiceMatching returned null."); |         dict = IOServiceMatching("IOUSBHostDevice"); | ||||||
|  |         if (dict == NULL) | ||||||
|  |         { | ||||||
|  |             error = error_create("IOServiceMatching returned null."); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Create an iterator for all the connected USB devices. |     // Create an iterator for all the connected USB devices. | ||||||
|   | |||||||
| @@ -2,9 +2,6 @@ | |||||||
|  |  | ||||||
| struct libusbp_serial_port | struct libusbp_serial_port | ||||||
| { | { | ||||||
|     // The I/O Registry ID of the IOBSDSerialClient. |  | ||||||
|     uint64_t id; |  | ||||||
|  |  | ||||||
|     // A port filename like "/dev/cu.usbmodemFD123". |     // A port filename like "/dev/cu.usbmodemFD123". | ||||||
|     char * port_name; |     char * port_name; | ||||||
| }; | }; | ||||||
| @@ -29,23 +26,16 @@ libusbp_error * libusbp_serial_port_create( | |||||||
|         return error_create("Device is null."); |         return error_create("Device is null."); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Add one to the interface number because that is what we need for the |  | ||||||
|     // typical case: The user specifies the lower of the two interface numbers, |  | ||||||
|     // which corresponds to the control interface of a CDC ACM device.  We |  | ||||||
|     // actually need the data interface because that is the one that the |  | ||||||
|     // IOSerialBSDClient lives under.  If this +1 causes any problems, it is |  | ||||||
|     // easy for the user to address it using an an ifdef.  Also, we might make |  | ||||||
|     // this function more flexible in the future if we need to handle different |  | ||||||
|     // types of serial devices with different drivers or interface layouts. |  | ||||||
|     interface_number += 1; |  | ||||||
|  |  | ||||||
|     libusbp_error * error = NULL; |     libusbp_error * error = NULL; | ||||||
|  |  | ||||||
|     libusbp_serial_port * new_port = calloc(1, sizeof(libusbp_serial_port)); |     libusbp_serial_port * new_port = NULL; | ||||||
|  |     if (error == NULL) | ||||||
|     if (new_port == NULL) |  | ||||||
|     { |     { | ||||||
|         error = &error_no_memory; |         new_port = calloc(1, sizeof(libusbp_serial_port)); | ||||||
|  |         if (new_port == NULL) | ||||||
|  |         { | ||||||
|  |             error = &error_no_memory; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Get the ID for the physical device. |     // Get the ID for the physical device. | ||||||
| @@ -62,19 +52,67 @@ libusbp_error * libusbp_serial_port_create( | |||||||
|         error = service_get_from_id(device_id, &device_service); |         error = service_get_from_id(device_id, &device_service); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Get an io_service_t for the interface. |     io_iterator_t iterator = MACH_PORT_NULL; | ||||||
|     io_service_t interface_service = MACH_PORT_NULL; |  | ||||||
|     if (error == NULL) |     if (error == NULL) | ||||||
|     { |     { | ||||||
|         error = service_get_usb_interface(device_service, interface_number, &interface_service); |         kern_return_t result = IORegistryEntryCreateIterator( | ||||||
|  |             device_service, kIOServicePlane, kIORegistryIterateRecursively, &iterator); | ||||||
|  |         if (result != KERN_SUCCESS) | ||||||
|  |         { | ||||||
|  |             error = error_create_mach(result, "Failed to get recursive iterator."); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Get an io_service_t for the IOSerialBSDClient |  | ||||||
|     io_service_t serial_service = MACH_PORT_NULL; |     io_service_t serial_service = MACH_PORT_NULL; | ||||||
|     if (error == NULL) |     int32_t current_interface = -1; | ||||||
|  |     int32_t last_acm_control_interface_with_no_port = -1; | ||||||
|  |     int32_t last_acm_data_interface = -1; | ||||||
|  |     while (error == NULL) | ||||||
|     { |     { | ||||||
|         error = service_get_child_by_class(interface_service, |         io_service_t service = IOIteratorNext(iterator); | ||||||
|             kIOSerialBSDServiceValue, &serial_service); |         if (service == MACH_PORT_NULL) { break; } | ||||||
|  |  | ||||||
|  |         if (IOObjectConformsTo(service, kIOUSBHostInterfaceClassName)) | ||||||
|  |         { | ||||||
|  |             error = get_int32(service, CFSTR("bInterfaceNumber"), ¤t_interface); | ||||||
|  |         } | ||||||
|  |         else if (IOObjectConformsTo(service, "AppleUSBACMControl")) | ||||||
|  |         { | ||||||
|  |             last_acm_control_interface_with_no_port = current_interface; | ||||||
|  |         } | ||||||
|  |         else if (IOObjectConformsTo(service, "AppleUSBACMData")) | ||||||
|  |         { | ||||||
|  |             last_acm_data_interface = current_interface; | ||||||
|  |         } | ||||||
|  |         else if (IOObjectConformsTo(service, kIOSerialBSDServiceValue)) | ||||||
|  |         { | ||||||
|  |           int32_t fixed_interface = current_interface; | ||||||
|  |           if (last_acm_data_interface == current_interface && | ||||||
|  |               last_acm_control_interface_with_no_port >= 0) | ||||||
|  |           { | ||||||
|  |               // We found an ACM control interface with no serial port, then | ||||||
|  |               // an ACM data interface with a serial port.  For consistency with | ||||||
|  |               // other operating systems, we will consider this serial port to | ||||||
|  |               // actually be associated with the control interface instead of the | ||||||
|  |               // data interface. | ||||||
|  |               fixed_interface = last_acm_control_interface_with_no_port; | ||||||
|  |           } | ||||||
|  |           last_acm_control_interface_with_no_port = -1; | ||||||
|  |  | ||||||
|  |           if (fixed_interface == interface_number) | ||||||
|  |           { | ||||||
|  |               // We found the serial port the user is looking for. | ||||||
|  |               serial_service = service; | ||||||
|  |               break; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         IOObjectRelease(service); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (error == NULL && serial_service == MACH_PORT_NULL) | ||||||
|  |     { | ||||||
|  |         error = error_create("Could not find entry with class IOSerialBSDClient."); | ||||||
|  |         error = error_add_code(error, LIBUSBP_ERROR_NOT_READY); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Get the port name. |     // Get the port name. | ||||||
| @@ -91,7 +129,7 @@ libusbp_error * libusbp_serial_port_create( | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (serial_service != MACH_PORT_NULL) { IOObjectRelease(serial_service); } |     if (serial_service != MACH_PORT_NULL) { IOObjectRelease(serial_service); } | ||||||
|     if (interface_service != MACH_PORT_NULL) { IOObjectRelease(interface_service); } |     if (iterator != MACH_PORT_NULL) { IOObjectRelease(iterator); } | ||||||
|     if (device_service != MACH_PORT_NULL) { IOObjectRelease(device_service); } |     if (device_service != MACH_PORT_NULL) { IOObjectRelease(device_service); } | ||||||
|     libusbp_serial_port_free(new_port); |     libusbp_serial_port_free(new_port); | ||||||
|  |  | ||||||
| @@ -125,11 +163,14 @@ libusbp_error * libusbp_serial_port_copy(const libusbp_serial_port * source, | |||||||
|     libusbp_error * error = NULL; |     libusbp_error * error = NULL; | ||||||
|  |  | ||||||
|     // Allocate memory for the new object. |     // Allocate memory for the new object. | ||||||
|     libusbp_serial_port * new_port = calloc(1, sizeof(libusbp_serial_port)); |     libusbp_serial_port * new_port = NULL; | ||||||
|  |     if (error == NULL) | ||||||
|     if (new_port == NULL) |  | ||||||
|     { |     { | ||||||
|         error = &error_no_memory; |         new_port = calloc(1, sizeof(libusbp_serial_port)); | ||||||
|  |         if (new_port == NULL) | ||||||
|  |         { | ||||||
|  |             error = &error_no_memory; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Copy the port name. |     // Copy the port name. | ||||||
|   | |||||||
| @@ -113,42 +113,79 @@ static libusbp_error * get_interface_composite( | |||||||
|         return error; |         return error; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Get a list of all the USB-related devices. |     unsigned int list_index = 0; | ||||||
|     HDEVINFO new_list = SetupDiGetClassDevs(NULL, "USB", NULL, |     HDEVINFO new_list = INVALID_HANDLE_VALUE; | ||||||
|         DIGCF_ALLCLASSES | DIGCF_PRESENT); |     DWORD i = 0; | ||||||
|     if (new_list == INVALID_HANDLE_VALUE) |  | ||||||
|     { |  | ||||||
|         return error_create_winapi( |  | ||||||
|             "Failed to get list of all USB devices while finding an interface."); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Iterate through the list until we find a device whose |     // Iterate through various device lists until we find a device whose | ||||||
|     // parent device is ours and which controls the interface |     // parent device is ours and which controls the interface | ||||||
|     // specified by the caller. |     // specified by the caller. | ||||||
|     for (DWORD i = 0; ; i++) |  | ||||||
|  |     while (true) | ||||||
|     { |     { | ||||||
|  |         if (new_list == INVALID_HANDLE_VALUE) | ||||||
|  |         { | ||||||
|  |             if (list_index == 0) | ||||||
|  |             { | ||||||
|  |                 // Get a list of all the USB-related devices. | ||||||
|  |                 // It includes native USB interfaces and usbser.sys ports but | ||||||
|  |                 // not FTDI ports. | ||||||
|  |                 new_list = SetupDiGetClassDevs(NULL, | ||||||
|  |                   "USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); | ||||||
|  |             } | ||||||
|  |             else if (list_index == 1) | ||||||
|  |             { | ||||||
|  |                 // Get a list of all the COM port devices. | ||||||
|  |                 // This includes FTDI and usbser.sys ports. | ||||||
|  |                 new_list = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, | ||||||
|  |                   NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); | ||||||
|  |             } | ||||||
|  |             else if (list_index == 2) | ||||||
|  |             { | ||||||
|  |                 // Get a list of all modem devices. | ||||||
|  |                 // Rationale: https://github.com/pyserial/pyserial/commit/7bb1dcc5aea16ca1c957690cb5276df33af1c286 | ||||||
|  |                 new_list = SetupDiGetClassDevs(&GUID_DEVINTERFACE_MODEM, | ||||||
|  |                   NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 // Could not find the child interface in any list. | ||||||
|  |                 // This could be a temporary condition. | ||||||
|  |                 libusbp_error * error = error_create("Could not find interface %d.", | ||||||
|  |                     interface_number); | ||||||
|  |                 error = error_add_code(error, LIBUSBP_ERROR_NOT_READY); | ||||||
|  |                 return error; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (new_list == INVALID_HANDLE_VALUE) | ||||||
|  |             { | ||||||
|  |                 return error_create_winapi( | ||||||
|  |                     "Failed to list devices to find an interface (%u).", | ||||||
|  |                     list_index); | ||||||
|  |             } | ||||||
|  |             i = 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         SP_DEVINFO_DATA device_info_data; |         SP_DEVINFO_DATA device_info_data; | ||||||
|         device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); |         device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); | ||||||
|         bool success = SetupDiEnumDeviceInfo(new_list, i, &device_info_data); |         bool success = SetupDiEnumDeviceInfo(new_list, i, &device_info_data); | ||||||
|         if (!success) |         if (!success) | ||||||
|         { |         { | ||||||
|             libusbp_error * error; |  | ||||||
|  |  | ||||||
|             if (GetLastError() == ERROR_NO_MORE_ITEMS) |             if (GetLastError() == ERROR_NO_MORE_ITEMS) | ||||||
|             { |             { | ||||||
|                 // Could not find the child interface.  This could be |                 // This list is done.  Try the next list. | ||||||
|                 // a temporary condition. |                 SetupDiDestroyDeviceInfoList(new_list); | ||||||
|                 error = error_create("Could not find interface %d.", |                 new_list = INVALID_HANDLE_VALUE; | ||||||
|                     interface_number); |                 list_index++; | ||||||
|                 error = error_add_code(error, LIBUSBP_ERROR_NOT_READY); |                 continue; | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                 error = error_create_winapi( |                 libusbp_error * error = error_create_winapi( | ||||||
|                     "Failed to get device info while finding an interface."); |                     "Failed to get device info to find an interface."); | ||||||
|  |                 SetupDiDestroyDeviceInfoList(new_list); | ||||||
|  |                 return error; | ||||||
|             } |             } | ||||||
|             SetupDiDestroyDeviceInfoList(new_list); |  | ||||||
|             return error; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         DEVINST parent_dev_inst; |         DEVINST parent_dev_inst; | ||||||
| @@ -162,6 +199,7 @@ static libusbp_error * get_interface_composite( | |||||||
|         if (parent_dev_inst != dev_inst) |         if (parent_dev_inst != dev_inst) | ||||||
|         { |         { | ||||||
|             // This device is not a child of our device. |             // This device is not a child of our device. | ||||||
|  |             i++; | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -179,9 +217,21 @@ static libusbp_error * get_interface_composite( | |||||||
|         unsigned int actual_interface_number; |         unsigned int actual_interface_number; | ||||||
|         int result = sscanf(device_id, "USB\\VID_%*4x&PID_%*4x&MI_%2x\\", |         int result = sscanf(device_id, "USB\\VID_%*4x&PID_%*4x&MI_%2x\\", | ||||||
|             &actual_interface_number); |             &actual_interface_number); | ||||||
|         if (result != 1 || actual_interface_number != interface_number) |         if (result != 1) | ||||||
|  |         { | ||||||
|  |           result = sscanf(device_id, "FTDIBUS\\%*[^\\]\\%x", | ||||||
|  |             &actual_interface_number); | ||||||
|  |           if (result != 1) | ||||||
|  |           { | ||||||
|  |             // Could not figure out the interface number. | ||||||
|  |             i++; | ||||||
|  |             continue; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         if (actual_interface_number != interface_number) | ||||||
|         { |         { | ||||||
|             // This is not the right interface. |             // This is not the right interface. | ||||||
|  |             i++; | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -124,6 +124,26 @@ libusbp_error * libusbp_serial_port_create( | |||||||
|     libusbp_string_free(usb_device_id); |     libusbp_string_free(usb_device_id); | ||||||
|     libusbp_serial_port_free(new_sp); |     libusbp_serial_port_free(new_sp); | ||||||
|  |  | ||||||
|  |     // FTDI devices like the FT232RL aren't actually composite but they look | ||||||
|  |     // like it on Windows because the serial port device is a child of the USB | ||||||
|  |     // device.  On Linux and macOS, those devices can be detected with | ||||||
|  |     // composite=false (or composite=true and interface_number=0). | ||||||
|  |     // This workaround allows that to work on Windows too, and it might make | ||||||
|  |     // this API easier to use for some non-FTDI devices too. | ||||||
|  |     if (error && !composite) | ||||||
|  |     { | ||||||
|  |         libusbp_error * error2 = libusbp_serial_port_create(device, 0, true, port); | ||||||
|  |         if (error2) | ||||||
|  |         { | ||||||
|  |             libusbp_error_free(error2); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             libusbp_error_free(error); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return error; |     return error; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,9 +1,8 @@ | |||||||
| INCLUDE (CheckIncludeFileCXX) | INCLUDE (CheckIncludeFileCXX) | ||||||
|  |  | ||||||
| # If catch.hpp is not present, we want to simply skip compiling the tests.  This | # If catch.hpp is not present, we want to simply skip compiling the tests. | ||||||
| # allows someone to compile and install libusbp without having catch installed. | # Download catch.hpp and put it in this directory: | ||||||
| # The header can either be installed in this directory or in a standard system | # https://raw.githubusercontent.com/catchorg/Catch2/v2.x/single_include/catch2/catch.hpp | ||||||
| # location. |  | ||||||
| set (CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}") | set (CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}") | ||||||
| CHECK_INCLUDE_FILE_CXX (catch.hpp HAVE_CATCH_FRAMEWORK) | CHECK_INCLUDE_FILE_CXX (catch.hpp HAVE_CATCH_FRAMEWORK) | ||||||
| if (NOT HAVE_CATCH_FRAMEWORK) | if (NOT HAVE_CATCH_FRAMEWORK) | ||||||
| @@ -11,8 +10,6 @@ if (NOT HAVE_CATCH_FRAMEWORK) | |||||||
|   return () |   return () | ||||||
| endif () | endif () | ||||||
|  |  | ||||||
| use_cxx11 () |  | ||||||
|  |  | ||||||
| set(USE_TEST_DEVICE_A FALSE CACHE BOOL | set(USE_TEST_DEVICE_A FALSE CACHE BOOL | ||||||
|   "Run tests that require Test Device A.") |   "Run tests that require Test Device A.") | ||||||
|  |  | ||||||
|   | |||||||
| @@ -486,6 +486,9 @@ TEST_CASE("async_in_pipe for an interrupt endpoint") | |||||||
|         // ms, a three-packet transfer will quickly receive those two packets |         // ms, a three-packet transfer will quickly receive those two packets | ||||||
|         // and then keep waiting for more. |         // and then keep waiting for more. | ||||||
|  |  | ||||||
|  |         // Previous versions of macOS returned one packet instead of two, | ||||||
|  |         // but this is no longer true on Darwin Kernel 22.1.0 (Oct 2022). | ||||||
|  |  | ||||||
|         // Pause the ADC for 100 ms. |         // Pause the ADC for 100 ms. | ||||||
|         handle.control_transfer(0x40, 0xA0, 100, 0); |         handle.control_transfer(0x40, 0xA0, 100, 0); | ||||||
|  |  | ||||||
| @@ -508,9 +511,6 @@ TEST_CASE("async_in_pipe for an interrupt endpoint") | |||||||
|  |  | ||||||
|                 #if defined(VBOX_LINUX_ON_WINDOWS) |                 #if defined(VBOX_LINUX_ON_WINDOWS) | ||||||
|                 CHECK(transferred == 0); |                 CHECK(transferred == 0); | ||||||
|                 #elif defined(__APPLE__) |  | ||||||
|                 CHECK(transferred == transfer_size); |  | ||||||
|                 CHECK(buffer[4] == 0xAB); |  | ||||||
|                 #else |                 #else | ||||||
|                 CHECK(transferred == transfer_size * 2); |                 CHECK(transferred == transfer_size * 2); | ||||||
|                 CHECK(buffer[4] == 0xAB); |                 CHECK(buffer[4] == 0xAB); | ||||||
| @@ -662,9 +662,10 @@ TEST_CASE("async_in_pipe for an interrupt endpoint") | |||||||
|         expected_message = "Asynchronous IN transfer failed.  " |         expected_message = "Asynchronous IN transfer failed.  " | ||||||
|             "Incorrect function.  Windows error code 0x1."; |             "Incorrect function.  Windows error code 0x1."; | ||||||
|         #elif defined(__linux__) |         #elif defined(__linux__) | ||||||
|         // This request results in an error in Linux but it is only detected |         // This request results in an error in Linux after some data is transferred. | ||||||
|         // after some data is transferred. |         // On some older Linux systems, expected_transferred was transfer_size + 1. | ||||||
|         expected_transferred = transfer_size + 1; |         // With Linux 5.15 on a Raspberry Pi 4, expected_transferred is transfer_size. | ||||||
|  |         expected_transferred = transfer_size; | ||||||
|         expected_message = "Asynchronous IN transfer failed.  " |         expected_message = "Asynchronous IN transfer failed.  " | ||||||
|             "The transfer overflowed.  Error code 75."; |             "The transfer overflowed.  Error code 75."; | ||||||
|         #elif defined(__APPLE__) |         #elif defined(__APPLE__) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user