mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Merge from master.
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. | ||||
| if (POLICY CMP0025) | ||||
| @@ -18,7 +18,7 @@ endif () | ||||
| project (libusbp) | ||||
|  | ||||
| set (LIBUSBP_VERSION_MAJOR 1) | ||||
| set (LIBUSBP_VERSION_MINOR 2) | ||||
| set (LIBUSBP_VERSION_MINOR 3) | ||||
| set (LIBUSBP_VERSION_PATCH 0) | ||||
|  | ||||
| # 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 | ||||
|   "Compile with special options needed for gcov.") | ||||
|  | ||||
| # Our C code uses features from the C99 standard. | ||||
| macro(use_c99) | ||||
|   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 (CMAKE_C_STANDARD 99) | ||||
| set (CMAKE_CXX_STANDARD 11) | ||||
|  | ||||
| set (LIBUSBP_VERSION ${LIBUSBP_VERSION_MAJOR}.${LIBUSBP_VERSION_MINOR}.${LIBUSBP_VERSION_PATCH}) | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
| # libusbp: Pololu USB Library | ||||
|  | ||||
| Version: 1.2.0<br/> | ||||
| Release date: 2020-11-16<br/> | ||||
| [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. | ||||
| @@ -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. | ||||
|   - 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. | ||||
| - 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. | ||||
|  | ||||
|  | ||||
| @@ -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` | ||||
|  | ||||
| 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. | ||||
|  | ||||
| @@ -167,6 +165,9 @@ For detailed documentation of this library, see the header files `libusb.h` and | ||||
|  | ||||
| ## 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): | ||||
|   * 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. | ||||
|   | ||||
| @@ -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) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(lsport lsport.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(lsusb lsusb.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(port_name port_name.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -41,7 +41,6 @@ extern "C" { | ||||
| #ifdef LIBUSBP_STATIC | ||||
| #  define LIBUSBP_API | ||||
| #else | ||||
| #error not static | ||||
| #  ifdef LIBUSBP_EXPORTS | ||||
| #    define LIBUSBP_API LIBUSBP_DLL_EXPORT | ||||
| #  else | ||||
|   | ||||
| @@ -107,7 +107,7 @@ namespace libusbp | ||||
|     { | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer. */ | ||||
|         explicit unique_pointer_wrapper(T * p = nullptr) noexcept | ||||
|         explicit unique_pointer_wrapper(T * p = NULL) noexcept | ||||
|             : pointer(p) | ||||
|         { | ||||
|         } | ||||
| @@ -133,9 +133,9 @@ namespace libusbp | ||||
|  | ||||
|         /*! Implicit conversion to bool.  Returns true if the underlying pointer | ||||
|          *  is not NULL. */ | ||||
|         explicit operator bool() const noexcept | ||||
|         operator bool() const noexcept | ||||
|         { | ||||
|             return pointer != nullptr; | ||||
|             return pointer != NULL; | ||||
|         } | ||||
|  | ||||
|         /*! Returns the underlying pointer. */ | ||||
| @@ -146,19 +146,19 @@ namespace libusbp | ||||
|  | ||||
|         /*! Sets the underlying pointer to the specified value, freeing the | ||||
|          * 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 = p; | ||||
|         } | ||||
|  | ||||
|         /*! 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. */ | ||||
|         T * pointer_release() noexcept | ||||
|         { | ||||
|             T * p = pointer; | ||||
|             pointer = nullptr; | ||||
|             pointer = NULL; | ||||
|             return p; | ||||
|         } | ||||
|  | ||||
| @@ -193,14 +193,14 @@ namespace libusbp | ||||
|     { | ||||
|     public: | ||||
|         /*! 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) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         /*! Move constructor. */ | ||||
|         unique_pointer_wrapper_with_copy( | ||||
|             unique_pointer_wrapper_with_copy && other) noexcept = default; | ||||
|             unique_pointer_wrapper_with_copy && other) = default; | ||||
|  | ||||
|         /*! Copy constructor */ | ||||
|         unique_pointer_wrapper_with_copy( | ||||
| @@ -228,13 +228,14 @@ namespace libusbp | ||||
|     { | ||||
|     public: | ||||
|         /*! 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) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         /*! Wrapper for libusbp_error_get_message(). */ | ||||
|         const char * what() const noexcept override { | ||||
|         virtual const char * what() const noexcept | ||||
|         { | ||||
|             return libusbp_error_get_message(pointer); | ||||
|         } | ||||
|  | ||||
| @@ -255,7 +256,7 @@ namespace libusbp | ||||
|     /*! \cond */ | ||||
|     inline void throw_if_needed(libusbp_error * err) | ||||
|     { | ||||
|         if (err != nullptr) | ||||
|         if (err != NULL) | ||||
|         { | ||||
|             throw error(err); | ||||
|         } | ||||
| @@ -267,7 +268,7 @@ namespace libusbp | ||||
|     { | ||||
|     public: | ||||
|         /*! 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) | ||||
|         { | ||||
|         } | ||||
| @@ -303,8 +304,8 @@ namespace libusbp | ||||
|         bool handle_finished_transfer(void * buffer, size_t * transferred, | ||||
|             error * transfer_error) | ||||
|         { | ||||
|             libusbp_error ** error_out = nullptr; | ||||
|             if (transfer_error != nullptr) | ||||
|             libusbp_error ** error_out = NULL; | ||||
|             if (transfer_error != NULL) | ||||
|             { | ||||
|                 transfer_error->pointer_reset(); | ||||
|                 error_out = transfer_error->pointer_to_pointer_get(); | ||||
| @@ -328,7 +329,7 @@ namespace libusbp | ||||
|     { | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer. */ | ||||
|         explicit device(libusbp_device * pointer = nullptr) : | ||||
|         explicit device(libusbp_device * pointer = NULL) : | ||||
|             unique_pointer_wrapper_with_copy(pointer) | ||||
|         { | ||||
|         } | ||||
| @@ -387,7 +388,7 @@ namespace libusbp | ||||
|         std::vector<device> vector; | ||||
|         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); | ||||
|         return vector; | ||||
| @@ -408,13 +409,13 @@ namespace libusbp | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer.  This object will free the pointer | ||||
|          *  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) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         /*! 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) | ||||
|         { | ||||
|             throw_if_needed(libusbp_generic_interface_create( | ||||
| @@ -448,13 +449,13 @@ namespace libusbp | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer.  This object will free the pointer | ||||
|          *  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) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         /*! 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)); | ||||
|         } | ||||
| @@ -486,9 +487,9 @@ namespace libusbp | ||||
|             uint8_t bRequest, | ||||
|             uint16_t wValue, | ||||
|             uint16_t wIndex, | ||||
|             void * buffer = nullptr, | ||||
|             void * buffer = NULL, | ||||
|             uint16_t wLength = 0, | ||||
|             size_t * transferred = nullptr) | ||||
|             size_t * transferred = NULL) | ||||
|         { | ||||
|             throw_if_needed(libusbp_control_transfer(pointer, | ||||
|                 bmRequestType, bRequest, wValue, wIndex, | ||||
| @@ -542,13 +543,13 @@ namespace libusbp | ||||
|     public: | ||||
|         /*! Constructor that takes a pointer.  This object will free the pointer | ||||
|          *  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) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         /*! 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) | ||||
|         { | ||||
|             throw_if_needed(libusbp_serial_port_create( | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| use_c99() | ||||
|  | ||||
| add_library (install_helper SHARED install_helper_windows.c dll.def) | ||||
|  | ||||
| target_link_libraries (install_helper setupapi msi) | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(test_async_in test_async_in.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(test_long_read test_long_read.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(test_long_write test_long_write.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| use_cxx11() | ||||
|  | ||||
| add_executable(test_transitions test_transitions.cpp) | ||||
|  | ||||
| include_directories ( | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| use_c99() | ||||
|  | ||||
| # Settings for GCC | ||||
| if (CMAKE_C_COMPILER_ID STREQUAL "GNU") | ||||
|   # 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); | ||||
|         if (result > 0) | ||||
|         { | ||||
|             outer_message_length = (size_t) result; | ||||
|             outer_message_length = result; | ||||
|         } | ||||
|         va_end(ap2); | ||||
|     } | ||||
|   | ||||
| @@ -37,7 +37,10 @@ libusbp_error * libusbp_find_device_with_vid_pid( | ||||
|  | ||||
|     libusbp_device ** new_list = NULL; | ||||
|     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); | ||||
|  | ||||
|   | ||||
| @@ -37,6 +37,7 @@ | ||||
| #include <usbioctl.h> | ||||
| #include <stringapiset.h> | ||||
| #include <winusb.h> | ||||
| #include <ntddmodm.h> | ||||
| #endif | ||||
|  | ||||
| #ifdef __linux__ | ||||
|   | ||||
| @@ -51,11 +51,14 @@ libusbp_error * async_in_transfer_create( | ||||
|     libusbp_error * error = NULL; | ||||
|  | ||||
|     // Allocate memory for the transfer struct. | ||||
|     async_in_transfer * new_transfer = calloc(1, sizeof(async_in_transfer)); | ||||
|  | ||||
|     if (new_transfer == NULL) | ||||
|     async_in_transfer * new_transfer = NULL; | ||||
|     if (error == 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. | ||||
|   | ||||
| @@ -25,9 +25,14 @@ libusbp_error * create_device(io_service_t service, libusbp_device ** device) | ||||
|     assert(service != MACH_PORT_NULL); | ||||
|     assert(device != NULL); | ||||
|  | ||||
|     libusbp_error * error = NULL; | ||||
|  | ||||
|     // Allocate the device. | ||||
|     libusbp_device * new_device = NULL; | ||||
|     libusbp_error * error = device_allocate(&new_device); | ||||
|     if (error == NULL) | ||||
|     { | ||||
|         error = device_allocate(&new_device); | ||||
|     } | ||||
|  | ||||
|     // Get the numeric IDs. | ||||
|     if (error == NULL) | ||||
| @@ -84,7 +89,10 @@ libusbp_error * libusbp_device_copy(const libusbp_device * source, libusbp_devic | ||||
|  | ||||
|     // Allocate the device. | ||||
|     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 | ||||
|     // 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; | ||||
|         uint16_t max_packet_size; | ||||
|         uint8_t interval; | ||||
|         kr = (*handle->ioh)->GetPipeProperties(handle->ioh, (UInt8) i, | ||||
|           &direction, &endpoint_number, &transfer_type, &max_packet_size, &interval); | ||||
|  | ||||
|         kern_return_t kr = (*handle->ioh)->GetPipeProperties(handle->ioh, i, | ||||
|             &direction, &endpoint_number, &transfer_type, &max_packet_size, &interval); | ||||
|         if (kr != KERN_SUCCESS) | ||||
|         { | ||||
|             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) | ||||
|             { | ||||
|                 handle->in_pipe_index[endpoint_number] = (uint8_t) i; | ||||
|                 handle->in_pipe_index[endpoint_number] = i; | ||||
|             } | ||||
|             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. | ||||
|     IOUSBDeviceInterface ** dev_handle = NULL; | ||||
|     IOCFPlugInInterface ** plug_in = NULL; | ||||
|     error = service_to_interface(service, | ||||
|         kIOUSBDeviceUserClientTypeID, | ||||
|         CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID197), | ||||
|         (void **)&dev_handle, | ||||
|         &plug_in); | ||||
|     if (error == NULL) | ||||
|     { | ||||
|         error = service_to_interface(service, | ||||
|             kIOUSBDeviceUserClientTypeID, | ||||
|             CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID197), | ||||
|             (void **)&dev_handle, | ||||
|             &plug_in); | ||||
|     } | ||||
|  | ||||
|     uint8_t config_num = 0; | ||||
|     if (error == NULL) | ||||
| @@ -170,7 +172,10 @@ static libusbp_error * set_configuration_and_get_service( | ||||
|  | ||||
|     // Get an io_service_t for the physical device. | ||||
|     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. | ||||
|     if (error == NULL) | ||||
| @@ -209,11 +214,13 @@ libusbp_error * libusbp_generic_handle_open( | ||||
|  | ||||
|     // Allocate memory for the handle. | ||||
|     libusbp_generic_handle * new_handle = NULL; | ||||
|     new_handle = calloc(1, sizeof(libusbp_generic_handle)); | ||||
|  | ||||
|     if (new_handle == NULL) | ||||
|     if (error == 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. | ||||
| @@ -323,11 +330,14 @@ libusbp_error * libusbp_generic_handle_set_timeout( | ||||
|  | ||||
|     libusbp_error * error = NULL; | ||||
|  | ||||
|     error = check_pipe_id(pipe_id); | ||||
|     if (error == NULL) | ||||
|     { | ||||
|         error = check_pipe_id(pipe_id); | ||||
|     } | ||||
|  | ||||
|     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) | ||||
|         { | ||||
| @@ -401,7 +411,7 @@ libusbp_error * libusbp_read_pipe( | ||||
|  | ||||
|     libusbp_error * error = NULL; | ||||
|  | ||||
|     if (size == 0) | ||||
|     if (error == NULL && size == 0) | ||||
|     { | ||||
|         error = error_create("Transfer size 0 is not allowed."); | ||||
|     } | ||||
| @@ -423,12 +433,12 @@ libusbp_error * libusbp_read_pipe( | ||||
|  | ||||
|     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 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]; | ||||
|         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); | ||||
|         if (transferred != NULL) { *transferred = iokit_size; } | ||||
|         if (kr != KERN_SUCCESS) | ||||
| @@ -464,7 +474,7 @@ libusbp_error * libusbp_write_pipe( | ||||
|  | ||||
|     libusbp_error * error = NULL; | ||||
|  | ||||
|     if (size > UINT32_MAX) | ||||
|     if (error == NULL && size > UINT32_MAX) | ||||
|     { | ||||
|         error = error_create("Transfer size is too large."); | ||||
|     } | ||||
| @@ -481,12 +491,12 @@ libusbp_error * libusbp_write_pipe( | ||||
|  | ||||
|     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 completion_timeout = handle->out_timeout[endpoint_number]; | ||||
|         uint32_t pipe_index = handle->out_pipe_index[endpoint_number]; | ||||
|         kern_return_t kr = (*handle->ioh)->WritePipeTO(handle->ioh, (UInt8) pipe_index, | ||||
|           (void *)buffer, (UInt32) size, no_data_timeout, completion_timeout); | ||||
|         kern_return_t kr = (*handle->ioh)->WritePipeTO(handle->ioh, pipe_index, | ||||
|           (void *)buffer, size, no_data_timeout, completion_timeout); | ||||
|         if (kr != KERN_SUCCESS) | ||||
|         { | ||||
|             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 endpoint_number = pipe_id & (uint8_t) MAX_ENDPOINT_NUMBER; | ||||
|     uint8_t endpoint_number = pipe_id & MAX_ENDPOINT_NUMBER; | ||||
|     if (pipe_id & 0x80) | ||||
|     { | ||||
|         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. | ||||
|         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. | ||||
|         io_service_t interface_service = MACH_PORT_NULL; | ||||
| @@ -146,7 +149,10 @@ libusbp_error * libusbp_generic_interface_copy( | ||||
|  | ||||
|     // Allocate the generic interface. | ||||
|     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. | ||||
|     if (error == NULL) | ||||
|   | ||||
| @@ -42,12 +42,14 @@ libusbp_error * service_get_usb_interface(io_service_t service, | ||||
|     libusbp_error * error = NULL; | ||||
|  | ||||
|     io_iterator_t iterator = MACH_PORT_NULL; | ||||
|     kern_return_t result = IORegistryEntryGetChildIterator( | ||||
|         service, kIOServicePlane, &iterator); | ||||
|  | ||||
|     if (result != KERN_SUCCESS) | ||||
|     if (error == NULL) | ||||
|     { | ||||
|         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. | ||||
| @@ -57,7 +59,7 @@ libusbp_error * service_get_usb_interface(io_service_t service, | ||||
|         if (candidate == MACH_PORT_NULL) { break; } | ||||
|  | ||||
|         // Filter out candidates that are not of class IOUSBInterface. | ||||
|         bool conforms = (bool) IOObjectConformsTo(candidate, kIOUSBInterfaceClassName); | ||||
|         bool conforms = IOObjectConformsTo(candidate, kIOUSBInterfaceClassName); | ||||
|         if (!conforms) | ||||
|         { | ||||
|             IOObjectRelease(candidate); | ||||
| @@ -88,54 +90,6 @@ libusbp_error * service_get_usb_interface(io_service_t service, | ||||
|     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( | ||||
|     io_service_t service, | ||||
|     CFUUIDRef pluginType, | ||||
| @@ -154,13 +108,15 @@ libusbp_error * service_to_interface( | ||||
|  | ||||
|     // Create the plug-in interface. | ||||
|     IOCFPlugInInterface ** new_plug_in = NULL; | ||||
|     kern_return_t kr = IOCreatePlugInInterfaceForService(service, | ||||
|         pluginType, kIOCFPlugInInterfaceID, | ||||
|         &new_plug_in, &score); | ||||
|  | ||||
|     if (kr != KERN_SUCCESS) | ||||
|     if (error == NULL) | ||||
|     { | ||||
|         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. | ||||
| @@ -223,7 +179,7 @@ libusbp_error * get_string(io_registry_entry_t entry, CFStringRef name, char ** | ||||
|  | ||||
|     libusbp_error * error = NULL; | ||||
|  | ||||
|     if (CFGetTypeID(cf_value) != CFStringGetTypeID()) | ||||
|     if (error == NULL && CFGetTypeID(cf_value) != CFStringGetTypeID()) | ||||
|     { | ||||
|         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); | ||||
|     } | ||||
|  | ||||
|     CFRelease(cf_value); | ||||
|     if (cf_value != NULL) { CFRelease(cf_value); } | ||||
|     return error; | ||||
| } | ||||
|  | ||||
| @@ -258,11 +214,14 @@ libusbp_error * get_int32(io_registry_entry_t entry, CFStringRef name, int32_t * | ||||
|  | ||||
|     libusbp_error * error = NULL; | ||||
|  | ||||
|     CFTypeRef cf_value = IORegistryEntryCreateCFProperty(entry, name, kCFAllocatorDefault, 0); | ||||
|  | ||||
|     if (cf_value == NULL) | ||||
|     CFTypeRef cf_value = NULL; | ||||
|     if (error == 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()) | ||||
| @@ -292,13 +251,16 @@ libusbp_error * get_uint16(io_registry_entry_t entry, CFStringRef name, uint16_t | ||||
|     libusbp_error * error = NULL; | ||||
|  | ||||
|     int32_t tmp; | ||||
|     error = get_int32(entry, name, &tmp); | ||||
|     if (error == NULL) | ||||
|     { | ||||
|         error = get_int32(entry, name, &tmp); | ||||
|     } | ||||
|  | ||||
|     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. | ||||
|         *value = (uint16_t) tmp; | ||||
|         *value = tmp; | ||||
|     } | ||||
|  | ||||
|     return error; | ||||
|   | ||||
| @@ -37,10 +37,13 @@ libusbp_error * libusbp_list_connected_devices( | ||||
|     // Create a dictionary that says "IOProviderClass" => "IOUSBDevice" | ||||
|     // This dictionary is CFReleased by IOServiceGetMatchingServices. | ||||
|     CFMutableDictionaryRef dict = NULL; | ||||
|     dict = IOServiceMatching("IOUSBHostDevice"); | ||||
|     if (dict == NULL) | ||||
|     if (error == 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. | ||||
|   | ||||
| @@ -2,9 +2,6 @@ | ||||
|  | ||||
| struct libusbp_serial_port | ||||
| { | ||||
|     // The I/O Registry ID of the IOBSDSerialClient. | ||||
|     uint64_t id; | ||||
|  | ||||
|     // A port filename like "/dev/cu.usbmodemFD123". | ||||
|     char * port_name; | ||||
| }; | ||||
| @@ -29,23 +26,16 @@ libusbp_error * libusbp_serial_port_create( | ||||
|         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_serial_port * new_port = calloc(1, sizeof(libusbp_serial_port)); | ||||
|  | ||||
|     if (new_port == NULL) | ||||
|     libusbp_serial_port * new_port = NULL; | ||||
|     if (error == 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. | ||||
| @@ -62,19 +52,67 @@ libusbp_error * libusbp_serial_port_create( | ||||
|         error = service_get_from_id(device_id, &device_service); | ||||
|     } | ||||
|  | ||||
|     // Get an io_service_t for the interface. | ||||
|     io_service_t interface_service = MACH_PORT_NULL; | ||||
|     io_iterator_t iterator = MACH_PORT_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; | ||||
|     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, | ||||
|             kIOSerialBSDServiceValue, &serial_service); | ||||
|         io_service_t service = IOIteratorNext(iterator); | ||||
|         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. | ||||
| @@ -91,7 +129,7 @@ libusbp_error * libusbp_serial_port_create( | ||||
|     } | ||||
|  | ||||
|     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); } | ||||
|     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; | ||||
|  | ||||
|     // Allocate memory for the new object. | ||||
|     libusbp_serial_port * new_port = calloc(1, sizeof(libusbp_serial_port)); | ||||
|  | ||||
|     if (new_port == NULL) | ||||
|     libusbp_serial_port * new_port = NULL; | ||||
|     if (error == 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. | ||||
|   | ||||
| @@ -113,42 +113,79 @@ static libusbp_error * get_interface_composite( | ||||
|         return error; | ||||
|     } | ||||
|  | ||||
|     // Get a list of all the USB-related devices. | ||||
|     HDEVINFO new_list = SetupDiGetClassDevs(NULL, "USB", NULL, | ||||
|         DIGCF_ALLCLASSES | DIGCF_PRESENT); | ||||
|     if (new_list == INVALID_HANDLE_VALUE) | ||||
|     { | ||||
|         return error_create_winapi( | ||||
|             "Failed to get list of all USB devices while finding an interface."); | ||||
|     } | ||||
|     unsigned int list_index = 0; | ||||
|     HDEVINFO new_list = INVALID_HANDLE_VALUE; | ||||
|     DWORD i = 0; | ||||
|  | ||||
|     // 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 | ||||
|     // 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; | ||||
|         device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); | ||||
|         bool success = SetupDiEnumDeviceInfo(new_list, i, &device_info_data); | ||||
|         if (!success) | ||||
|         { | ||||
|             libusbp_error * error; | ||||
|  | ||||
|             if (GetLastError() == ERROR_NO_MORE_ITEMS) | ||||
|             { | ||||
|                 // Could not find the child interface.  This could be | ||||
|                 // a temporary condition. | ||||
|                 error = error_create("Could not find interface %d.", | ||||
|                     interface_number); | ||||
|                 error = error_add_code(error, LIBUSBP_ERROR_NOT_READY); | ||||
|                 // This list is done.  Try the next list. | ||||
|                 SetupDiDestroyDeviceInfoList(new_list); | ||||
|                 new_list = INVALID_HANDLE_VALUE; | ||||
|                 list_index++; | ||||
|                 continue; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 error = error_create_winapi( | ||||
|                     "Failed to get device info while finding an interface."); | ||||
|                 libusbp_error * error = error_create_winapi( | ||||
|                     "Failed to get device info to find an interface."); | ||||
|                 SetupDiDestroyDeviceInfoList(new_list); | ||||
|                 return error; | ||||
|             } | ||||
|             SetupDiDestroyDeviceInfoList(new_list); | ||||
|             return error; | ||||
|         } | ||||
|  | ||||
|         DEVINST parent_dev_inst; | ||||
| @@ -162,6 +199,7 @@ static libusbp_error * get_interface_composite( | ||||
|         if (parent_dev_inst != dev_inst) | ||||
|         { | ||||
|             // This device is not a child of our device. | ||||
|             i++; | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
| @@ -179,9 +217,21 @@ static libusbp_error * get_interface_composite( | ||||
|         unsigned int actual_interface_number; | ||||
|         int result = sscanf(device_id, "USB\\VID_%*4x&PID_%*4x&MI_%2x\\", | ||||
|             &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. | ||||
|             i++; | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -124,6 +124,26 @@ libusbp_error * libusbp_serial_port_create( | ||||
|     libusbp_string_free(usb_device_id); | ||||
|     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; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,9 +1,8 @@ | ||||
| INCLUDE (CheckIncludeFileCXX) | ||||
|  | ||||
| # If catch.hpp is not present, we want to simply skip compiling the tests.  This | ||||
| # allows someone to compile and install libusbp without having catch installed. | ||||
| # The header can either be installed in this directory or in a standard system | ||||
| # location. | ||||
| # If catch.hpp is not present, we want to simply skip compiling the tests. | ||||
| # Download catch.hpp and put it in this directory: | ||||
| # https://raw.githubusercontent.com/catchorg/Catch2/v2.x/single_include/catch2/catch.hpp | ||||
| set (CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}") | ||||
| CHECK_INCLUDE_FILE_CXX (catch.hpp HAVE_CATCH_FRAMEWORK) | ||||
| if (NOT HAVE_CATCH_FRAMEWORK) | ||||
| @@ -11,8 +10,6 @@ if (NOT HAVE_CATCH_FRAMEWORK) | ||||
|   return () | ||||
| endif () | ||||
|  | ||||
| use_cxx11 () | ||||
|  | ||||
| set(USE_TEST_DEVICE_A FALSE CACHE BOOL | ||||
|   "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 | ||||
|         // 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. | ||||
|         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) | ||||
|                 CHECK(transferred == 0); | ||||
|                 #elif defined(__APPLE__) | ||||
|                 CHECK(transferred == transfer_size); | ||||
|                 CHECK(buffer[4] == 0xAB); | ||||
|                 #else | ||||
|                 CHECK(transferred == transfer_size * 2); | ||||
|                 CHECK(buffer[4] == 0xAB); | ||||
| @@ -662,9 +662,10 @@ TEST_CASE("async_in_pipe for an interrupt endpoint") | ||||
|         expected_message = "Asynchronous IN transfer failed.  " | ||||
|             "Incorrect function.  Windows error code 0x1."; | ||||
|         #elif defined(__linux__) | ||||
|         // This request results in an error in Linux but it is only detected | ||||
|         // after some data is transferred. | ||||
|         expected_transferred = transfer_size + 1; | ||||
|         // This request results in an error in Linux after some data is transferred. | ||||
|         // On some older Linux systems, expected_transferred was 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.  " | ||||
|             "The transfer overflowed.  Error code 75."; | ||||
|         #elif defined(__APPLE__) | ||||
|   | ||||
| @@ -107,8 +107,8 @@ Bytes greaseWeazleToFluxEngine(const Bytes& gwdata, nanoseconds_t clock) | ||||
|  | ||||
| 		if (event) | ||||
| 		{ | ||||
| 			uint32_t index_fl = (index_gw * clock) / NS_PER_TICK; | ||||
| 			uint32_t ticks_fl = (ticks_gw * clock) / NS_PER_TICK; | ||||
| 			uint32_t index_fl = round((index_gw * clock) / NS_PER_TICK); | ||||
| 			uint32_t ticks_fl = round((ticks_gw * clock) / NS_PER_TICK); | ||||
| 			if (index_gw != ~0) | ||||
| 			{ | ||||
| 				if (index_fl < ticks_fl) | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| $(OBJDIR)/tests/%.log: $(OBJDIR)/tests/%.exe | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo TEST $* | ||||
| 	@$< > $@ | ||||
| 	@$< | ||||
|  | ||||
| declare-test = $(eval $(declare-test-impl)) | ||||
| define declare-test-impl | ||||
|   | ||||
		Reference in New Issue
	
	Block a user