mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -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.
|
||||
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;
|
||||
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,12 +51,15 @@ 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));
|
||||
|
||||
async_in_transfer * new_transfer = NULL;
|
||||
if (error == NULL)
|
||||
{
|
||||
new_transfer = calloc(1, sizeof(async_in_transfer));
|
||||
if (new_transfer == NULL)
|
||||
{
|
||||
error = &error_no_memory;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate memory for the buffer.
|
||||
if (error == NULL)
|
||||
|
||||
@@ -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;
|
||||
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,
|
||||
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;
|
||||
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;
|
||||
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,12 +214,14 @@ libusbp_error * libusbp_generic_handle_open(
|
||||
|
||||
// Allocate memory for the handle.
|
||||
libusbp_generic_handle * new_handle = NULL;
|
||||
if (error == NULL)
|
||||
{
|
||||
new_handle = calloc(1, sizeof(libusbp_generic_handle));
|
||||
|
||||
if (new_handle == NULL)
|
||||
{
|
||||
error = &error_no_memory;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the io_service_t representing the IOUSBInterface.
|
||||
io_service_t service = MACH_PORT_NULL;
|
||||
@@ -323,11 +330,14 @@ libusbp_error * libusbp_generic_handle_set_timeout(
|
||||
|
||||
libusbp_error * error = NULL;
|
||||
|
||||
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;
|
||||
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;
|
||||
if (error == NULL)
|
||||
{
|
||||
error = generic_interface_allocate(&new_gi);
|
||||
}
|
||||
|
||||
// Copy the simple fields.
|
||||
if (error == NULL)
|
||||
|
||||
@@ -42,13 +42,15 @@ libusbp_error * service_get_usb_interface(io_service_t service,
|
||||
libusbp_error * error = NULL;
|
||||
|
||||
io_iterator_t iterator = MACH_PORT_NULL;
|
||||
if (error == NULL)
|
||||
{
|
||||
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.
|
||||
while (error == NULL)
|
||||
@@ -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,14 +108,16 @@ libusbp_error * service_to_interface(
|
||||
|
||||
// Create the plug-in interface.
|
||||
IOCFPlugInInterface ** new_plug_in = NULL;
|
||||
if (error == NULL)
|
||||
{
|
||||
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.
|
||||
if (error == NULL)
|
||||
@@ -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,12 +214,15 @@ 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);
|
||||
|
||||
CFTypeRef cf_value = NULL;
|
||||
if (error == NULL)
|
||||
{
|
||||
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;
|
||||
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,11 +37,14 @@ libusbp_error * libusbp_list_connected_devices(
|
||||
// Create a dictionary that says "IOProviderClass" => "IOUSBDevice"
|
||||
// This dictionary is CFReleased by IOServiceGetMatchingServices.
|
||||
CFMutableDictionaryRef dict = NULL;
|
||||
if (error == NULL)
|
||||
{
|
||||
dict = IOServiceMatching("IOUSBHostDevice");
|
||||
if (dict == NULL)
|
||||
{
|
||||
error = error_create("IOServiceMatching returned null.");
|
||||
}
|
||||
}
|
||||
|
||||
// Create an iterator for all the connected USB devices.
|
||||
io_iterator_t iterator = MACH_PORT_NULL;
|
||||
|
||||
@@ -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,24 +26,17 @@ 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));
|
||||
|
||||
libusbp_serial_port * new_port = NULL;
|
||||
if (error == NULL)
|
||||
{
|
||||
new_port = calloc(1, sizeof(libusbp_serial_port));
|
||||
if (new_port == NULL)
|
||||
{
|
||||
error = &error_no_memory;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the ID for the physical device.
|
||||
uint64_t device_id;
|
||||
@@ -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,12 +163,15 @@ 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));
|
||||
|
||||
libusbp_serial_port * new_port = NULL;
|
||||
if (error == NULL)
|
||||
{
|
||||
new_port = calloc(1, sizeof(libusbp_serial_port));
|
||||
if (new_port == NULL)
|
||||
{
|
||||
error = &error_no_memory;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the port name.
|
||||
if (error == NULL)
|
||||
|
||||
@@ -113,43 +113,80 @@ static libusbp_error * get_interface_composite(
|
||||
return error;
|
||||
}
|
||||
|
||||
unsigned int list_index = 0;
|
||||
HDEVINFO new_list = INVALID_HANDLE_VALUE;
|
||||
DWORD i = 0;
|
||||
|
||||
// Iterate through various device lists until we find a device whose
|
||||
// parent device is ours and which controls the interface
|
||||
// specified by the caller.
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (new_list == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (list_index == 0)
|
||||
{
|
||||
// Get a list of all the USB-related devices.
|
||||
HDEVINFO new_list = SetupDiGetClassDevs(NULL, "USB", NULL,
|
||||
DIGCF_ALLCLASSES | DIGCF_PRESENT);
|
||||
// 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 get list of all USB devices while finding an interface.");
|
||||
"Failed to list devices to find an interface (%u).",
|
||||
list_index);
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
|
||||
// Iterate through the list until we find a device whose
|
||||
// parent device is ours and which controls the interface
|
||||
// specified by the caller.
|
||||
for (DWORD i = 0; ; i++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
DEVINST parent_dev_inst;
|
||||
cr = CM_Get_Parent(&parent_dev_inst, device_info_data.DevInst, 0);
|
||||
@@ -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__)
|
||||
|
||||
Reference in New Issue
Block a user