Files
fluxengine/dep/libusbp/include/libusbp.h
David Given d157b7b05d Make libusbp work on Windows; rework the Microsoft-specific bits of the
firmware to match. This does at least allow us to get rid of the patcher.
2021-12-12 17:25:24 +00:00

738 lines
29 KiB
C

// Copyright (C) Pololu Corporation. See www.pololu.com for details.
/*! \file libusbp.h
*
* This header file provides the C API for libusbp.
*/
#pragma once
/*! The major component of libusbp's version number. In accordance with
* semantic versioning, this gets incremented every time there is a breaking
* change. */
#define LIBUSBP_VERSION_MAJOR 1
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef _WIN32
#include <wtypesbase.h>
#endif
#ifdef _WIN32
# define LIBUSBP_DLL_EXPORT __declspec(dllexport)
# define LIBUSBP_DLL_IMPORT __declspec(dllimport)
#else
# define LIBUSBP_DLL_IMPORT __attribute__((visibility ("default")))
# define LIBUSBP_DLL_EXPORT __attribute__((visibility ("default")))
#endif
#ifdef _MSC_VER
#define LIBUSBP_WARN_UNUSED _Check_return_
#else
#define LIBUSBP_WARN_UNUSED __attribute__((warn_unused_result))
#endif
#ifdef LIBUSBP_STATIC
# define LIBUSBP_API
#else
#error not static
# ifdef LIBUSBP_EXPORTS
# define LIBUSBP_API LIBUSBP_DLL_EXPORT
# else
# define LIBUSBP_API LIBUSBP_DLL_IMPORT
# endif
#endif
/*! Some functions in this library return strings to the caller via a char **
* argument. If the function call was successful, it is the caller's
* responsibility to free those strings by passing them to this function.
* Passing the NULL pointer to this function is OK. Do not pass any strings to
* this function unless they were previously returned by a call to this
* library. Do not free the same non-NULL string twice. */
LIBUSBP_API
void libusbp_string_free(char *);
/** libusbp_error **************************************************************/
/*! A libusbp_error object represents an error that occurred in the library.
* Many functions return a libusbp_error pointer as a return value. The
* convention is that a NULL pointer indicates success. If the pointer is not
* NULL, the caller needs to free it at some point by calling
* libusbp_error_free().
*
* NULL is a valid value for a libusbp_error pointer, and can be passed to any
* function in this library that takes a libusbp_error pointer. */
typedef struct libusbp_error
libusbp_error;
/*! Each ::libusbp_error can have 0 or more error codes that give additional
* information about the error that might help the caller take the right action
* when the error occurs. This enum defines which error codes are possible. */
enum libusbp_error_code
{
/*! There were problems allocating memory. A memory shortage might be the
* root cause of the error, or there might be another error that is masked
* by the memory problems. */
LIBUSBP_ERROR_MEMORY = 1,
/*! It is possible that the error was caused by a temporary condition, such
* as the operating system taking some time to initialize drivers. Any
* function that could return this error will say so explicitly in its
* documentation so you do not have to worry about handling it in too many
* places. */
LIBUSBP_ERROR_NOT_READY = 2,
/*! Access was denied. A common cause of this error on Windows is that
* another application has a handle open to the same device. */
LIBUSBP_ERROR_ACCESS_DENIED = 3,
/*! The device does not have a serial number. */
LIBUSBP_ERROR_NO_SERIAL_NUMBER = 4,
/*! The device took too long to respond to a request or transfer data. */
LIBUSBP_ERROR_TIMEOUT = 5,
/*! The error might have been caused by the device being disconnected, but
* it is possible it was caused by something else. */
LIBUSBP_ERROR_DEVICE_DISCONNECTED = 6,
/*! The error might have been caused by the host receiving a STALL packet
* from the device, but it is possible it was caused by something else. */
LIBUSBP_ERROR_STALL = 7,
/*! The error might have been caused by the transfer getting cancelled from
* the host side. Some data might have been transferred anyway. */
LIBUSBP_ERROR_CANCELLED = 8,
};
/*! Attempts to copy an error. If you copy a NULL ::libusbp_error
* pointer, the result will also be NULL. If you copy a non-NULL ::libusbp_error
* pointer, the result will be non-NULL, but if there are issues allocating
* memory, then the copied error might have different properties than the
* original error, and it will have the ::LIBUSBP_ERROR_MEMORY code.
*
* It is the caller's responsibility to free the copied error. */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_error_copy(const libusbp_error *);
/*! Frees a returned error object. Passing the NULL pointer to this function is
* OK. Do not free the same non-NULL error twice. */
LIBUSBP_API
void libusbp_error_free(libusbp_error *);
/*! Returns true if the error has specified error code. The error codes are
* listed in the ::libusbp_error_code enum. */
LIBUSBP_API bool libusbp_error_has_code(const libusbp_error *, uint32_t code);
/*! Returns an English-language ASCII-encoded string describing the error. The
* message consists of one or more sentences. If there are multiple sentences,
* the earlier ones will typically explain the context that the error happened
* in.
*
* The returned pointer will be valid until the error is freed, at which point
* it might become invalid. Do not pass the returned pointer to
* libusbp_string_free(). */
LIBUSBP_API const char * libusbp_error_get_message(const libusbp_error *);
/** libusbp_async_in_pipe ******************************************************/
/*! A libusbp_async_in_pipe is an object that holds the memory and other data
* structures for a set of asynchronous USB requests to read data from a
* non-zero endpoint. It can be used to read data from a bulk or IN endpoint
* with high throughput. */
typedef struct libusbp_async_in_pipe
libusbp_async_in_pipe;
/*! Closes the pipe immediately. Note that if the pipe has any
* pending transfers, then it is possible that they cannot be freed
* by this function. Freeing a pipe with pending transfers could
* cause a memory leak, but is otherwise safe. */
LIBUSBP_API
void libusbp_async_in_pipe_close(libusbp_async_in_pipe *);
/*! Allocates buffers and other data structures for performing multiple
* concurrent transfers on the pipe.
*
* The @a transfer_count parameter specifies how many transfers to allocate. You
* can also think of this as the maximum number of concurrent transfers that can
* be active at the same time.
*
* The @a transfer_size parameter specifies how large each transfer's buffer should
* be, and is also the number of bytes that will be requested from the operating
* system when the transfer is submitted.
*
* It is best to set the transfer size to a multiple of the maximum packet size
* of the endpoint. Otherwise, you might get an error when the device sends
* more data than can fit in the transfer's buffer. This type of error is
* called an overflow.
*
* If you want to be reading the pipe every millisecond without gaps, you should
* set the transfer count high enough so that it would take about 100 ms to 250
* ms to finish all the transfers. As long as the operating system runs your
* process that often, you should be able to keep the USB host controller busy
* permanently. (Though we have observed gaps in the transfers when trying to
* do this inside a VirtualBox machine.)
*
* You should not set the transfer count too high, or else it might end up
* taking a long time to cancel the transfers when you are closing the pipe. */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_async_in_pipe_allocate_transfers(
libusbp_async_in_pipe *,
size_t transfer_count,
size_t transfer_size);
/*! Starts reading data from the pipe. */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_async_in_pipe_start_endless_transfers(
libusbp_async_in_pipe *);
/*! Checks for new events, such as a transfer completing. This
* function and libusbp_async_in_pipe_handle_finished_transfer() should
* be called regularly in order to get data from the pipe. */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_async_in_pipe_handle_events(libusbp_async_in_pipe *);
/*! Retrieves a boolean saying whether there are any pending
* transfers. A pending transfer is a transfer that was submitted to
* the operating system, and it may have been completed, but it has
* not been passed to the caller yet via
* libusbp_async_in_pipe_handle_finished_transfer(). */
LIBUSBP_API LIBUSBP_WARN_UNUSED libusbp_error *
libusbp_async_in_pipe_has_pending_transfers(
libusbp_async_in_pipe *,
bool * result);
/*! Checks to see if there is a finished transfer that can be handled.
* If there is one, then this function retrieves the data from the
* transfer, the number of bytes transferred, and any error that might
* have occurred related to the transfer.
*
* @param finished An optional output pointer used to return a pointer that
* indicates whether a transfer was finished. If the returned value is false,
* then no transfer was finished, and there is no transfer_error or data to
* handle.
*
* @param buffer An optional output pointer used to return the data
* from the transfer. The buffer must be at least as large as the
* transfer size specifed when
* libusbp_async_in_pipe_allocate_transfers was called.
*
* @param transferred An optional output pointer used to return the
* number of bytes transferred.
*
* @param transfer_error An optional pointer used to return an error
* related to the transfer, such as a timeout or a cancellation. If
* this pointer is provided, and a non-NULL error is returned via it,
* then the error must later be freed with libusbp_error_free(). There
* will never be a non-NULL transfer error if there is a regular error
* returned as the return value of this function. */
LIBUSBP_API LIBUSBP_WARN_UNUSED libusbp_error *
libusbp_async_in_pipe_handle_finished_transfer(
libusbp_async_in_pipe *,
bool * finished,
void * buffer,
size_t * transferred,
libusbp_error ** transfer_error);
/*! Cancels all the transfers for this pipe. The cancellation is
* asynchronous, so it won't have an immediate effect. If you want
* to actually make sure that all the transfers get cancelled, you
* will need to call libusbp_async_in_pipe_handle_events() and
* libusbp_async_in_pipe_handle_finished_transfer() repeatedly until
* libusbp_async_in_pipe_has_pending_transfers() indicates there are
* no pending transfers left. */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_async_in_pipe_cancel_transfers(libusbp_async_in_pipe *);
/** libusbp_device *************************************************************/
/*! Represents a single USB device. A composite device with multiple functions
* is represented by a single libusbp_device object.
*
* A NULL libusbp_device pointer is valid and can be passed to any function in
* this library that takes such pointers. */
typedef struct libusbp_device
libusbp_device;
/*! Finds all the USB devices connected to the computer and returns a list of them.
*
* The optional @a device_count parameter is used to return the number of
* devices in the list. The list is actually one element larger because it ends
* with a NULL pointer.
*
* If this function is successful (the returned error pointer is NULL), then you
* must later free each device by calling libusbp_device_free() and free the
* list by calling libusbp_list_free(). The order in which the retrieved
* objects are freed does not matter. */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_list_connected_devices(
libusbp_device *** device_list,
size_t * device_count);
/*! Frees a device list returned by libusbp_list_connected_device(). */
LIBUSBP_API
void libusbp_list_free(libusbp_device ** list);
/*! Finds a device with the specified vendor ID and product ID and returns a
* pointer to it. If no device can be found, returns a NULL pointer. If the
* retrieved device pointer is not NULL, you must free it later by calling
* libusbp_device_free(). The retrieved device pointer will always be NULL if
* an error is returned. */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_find_device_with_vid_pid(
uint16_t vendor_id,
uint16_t product_id,
libusbp_device ** device);
/*! Makes a copy of a device object. If this function is successful, you will
* need to free the copy by calling libusbp_device_free() at some point. */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_device_copy(
const libusbp_device * source,
libusbp_device ** dest);
/*! Frees a device object. Passing a NULL pointer to this function is OK. Do
* not free the same non-NULL device twice. */
LIBUSBP_API void libusbp_device_free(libusbp_device *);
/*! Gets the USB vendor ID of the device (idVendor). */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_device_get_vendor_id(
const libusbp_device *,
uint16_t * vendor_id);
/*! Gets the USB product ID of the device (idProduct). */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_device_get_product_id(
const libusbp_device *,
uint16_t * product_id);
/*! Gets the USB revision code of the device (bcdDevice). */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_device_get_revision(
const libusbp_device *,
uint16_t * revision);
/*! Gets the serial number of the device as an ASCII-encoded string.
*
* On Windows, this just returns the segment of the Device Instance ID after the
* last slash. If the device does not have a serial number, it will return some
* other type of identifier that contains andpersands (&). Windows ignores
* serial numbers with invalid characters in them. For more information, see:
*
* https://msdn.microsoft.com/en-us/library/windows/hardware/dn423379#usbsn
*
* On other systems, if the device does not have a serial number, then this
* function returns an error with the code ::LIBUSBP_ERROR_NO_SERIAL_NUMBER.
*
* (Most applications should only call this function on specific USB devices
* that are already known to have serial numbers, in which case the lack of a
* serial number really does indicate a failure.)
*
* You should free the returned string by calling libusbp_string_free(). */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_device_get_serial_number(
const libusbp_device *,
char ** serial_number);
/*! Gets an operating system-specific string that identifies the device.
*
* Note that the level of specificity provided by the ID depends on the system
* you are on, and whether your device has a USB serial number. As long as the
* device remains connected to the bus, this ID is not expected to change and
* there should be no other devices that have the same ID. However, if the
* device gets disconnected from the bus, it may be possible for the ID to be
* reused by another device.
*
* @b Windows: This will be a device instance ID, and it will look something
* like this:
*
* <pre>
* USB\\VID_1FFB&PID_DA01\6&11A23516&18&0000
* </pre>
*
* If your device has a serial number, the part after the slash will be the
* serial number. Otherwise, it will be a string with andpersands in it.
*
* @b Linux: This will be a sysfs path, and it will look like something like
* this:
*
* <pre>
* /sys/devices/pci0000:00/0000:00:06.0/usb1/1-2
* </pre>
*
* <b>macOS:</b> This will be an integer from
* IORegistryEntryGetRegistryEntryID, formatted as a lower-case hex number with
* no leading zeros. It will look something like this:
*
* <pre>
* 10000021a
* </pre>
*/
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_device_get_os_id(
const libusbp_device *,
char ** id);
/** libusbp_generic_interface **************************************************/
/*! Represents a generic or vendor-defined interface of a USB device. A null
* libusbp_generic_interface pointer is valid and can be passed to any function
* in this library that takes such pointers. */
typedef struct libusbp_generic_interface
libusbp_generic_interface;
/*! Creates a generic interface object for a specified interface of the
* specified USB device. This function does as many checks as possible to make
* sure that a handle to the interface could be opened, without actually opening
* it yet.
*
* On all platforms, if a record of the interface cannot be found, then an error
* is returned with the code LIBUSBP_ERROR_NOT_READY, because this could just be
* a temporary condition that happens right after the device is plugged in.
*
* On Windows, the generic interface must use the WinUSB driver, or this
* function will fail. If it is using no driver, that could be a temporary
* condition, and the error returned will use the LIBUSBP_ERROR_NOT_READY error
* code.
*
* On Linux, if the corresponding devnode file does not exist, an error with
* code LIBUSBP_ERROR_NOT_READY is returned. If the interface is assigned to a
* driver that is not "usbfs", an error is returned.
*
* On macOS, we do not have any additional checks beyond just making sure
* that an entry for the interface is found. For non-composite devices, that
* check is deferred until a handle is opened.
*
* @param interface_number The lowest @a bInterfaceNumber for the interfaces in
* the USB function you want to use.
*
* @param composite Should be true if the device is composite, and false
* otherwise.
*
* The returned object must be freed with libusbp_generic_interface_free(). */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_generic_interface_create(
const libusbp_device *,
uint8_t interface_number,
bool composite,
libusbp_generic_interface **);
/*! Frees the specified generic interface object. Passing the NULL pointer to
* this function is OK. Do not free the same non-NULL pointer twice. */
LIBUSBP_API void libusbp_generic_interface_free(libusbp_generic_interface *);
/*! Makes a copy of the generic interface object. The copy must be freed with
* libusbp_generic_interface_free(). */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_generic_interface_copy(
const libusbp_generic_interface * source,
libusbp_generic_interface ** dest);
/*! Returns an operating system-specific string that can be used to uniquely
* identify this generic interface.
*
* <b>Windows:</b> This will be a device instance ID specific to this interface, and
* it will look something like this:
*
* <pre>
* USB\\VID_1FFB&PID_DA01&MI_00\6&11A23516&18&0000
* </pre>
*
* <b>Linux:</b> This will be a sysfs path specific to this interface, and it will
* look like something like this:
*
* <pre>
* /sys/devices/pci0000:00/0000:00:06.0/usb1/1-2/1-2:1.0
* </pre>
*
* <b>macOS:</b> This will be an integer from
* IORegistryEntryGetRegistryEntryID, formatted as a lower-case hex number with
* no leading zeros. It will look something like this:
*
* <pre>
* 10000021a
* </pre>
*/
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_generic_interface_get_os_id(
const libusbp_generic_interface *,
char ** id);
/*! Returns an operating system-specific filename corresponding to this
* interface.
*
* <b>Windows:</b> This will be the name of a file you can use with CreateFile to
* access the device, and it will look something like this:
*
* <pre>
* \\\\?\\usb#vid_1ffb&pid_da01&mi_00#6&11a23516&18&0000#{99c4bbb0-e925-4397-afee-981cd0702163}
* </pre>
*
* <b>Linux:</b> this will return a device node file name that represents the
* overall USB device. It will look something like:
*
* <pre>
* /dev/bus/usb/001/007
* </pre>
*
* <b>macOS:</b> This will be an integer from
* IORegistryEntryGetRegistryEntryID, formatted as a lower-case hex number with
* no leading zeros. It will look something like this:
*
* <pre>
* 10000021a
* </pre>
*/
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_generic_interface_get_os_filename(
const libusbp_generic_interface *,
char ** filename);
/** libusbp_generic_handle *****************************************************/
/*! Represents a generic handle to a USB device. This handle can be used to
* perform operations such as control transfers and reading and writing data
* from non-zero endpoints.
*
* NULL is a valid value for a libusbp_generic_handle pointer, and can be passed
* in any functions of this library that take a libusbp_generic_handle
* pointer. */
typedef struct libusbp_generic_handle
libusbp_generic_handle;
/*! Opens a generic handle to the specified interface of a USB device which can
* be used to perform USB I/O operations.
*
* The handle must later be closed with libusbp_generic_handle_close().
*
* On Windows, for devices using WinUSB, if another application has a handle
* open already when this function is called, then this function will fail and
* the returned error will have code ::LIBUSBP_ERROR_ACCESS_DENIED.
*
* On macOS, this function will set the device's configuration to 1 as a
* side effect in case it is not already configured. */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_generic_handle_open(
const libusbp_generic_interface *,
libusbp_generic_handle **);
/*! Closes and frees the specified generic handle. It is OK to pass NULL to
* this function. Do not close the same non-NULL handle twice. All
* ::libusbp_async_in_pipe objects created by the handle must be closed before
* closing the handle. */
LIBUSBP_API
void libusbp_generic_handle_close(
libusbp_generic_handle *);
/*! Creates a new asynchronous pipe object for reading data in from the device
* on one of its bulk or interrupt IN endpoints.
*
* The behavior of this library is unspecified if you use both an asynchronous
* IN pipe and synchronous reads with libusbp_read_pipe() on the same pipe of
* the same generic handle. One reason for that is because for WinUSB devices,
* this function enables RAW_IO for the pipe, and it does not turn off RAW_IO
* again after the pipe is closed. So the behavior of libusbp_read_pipe() could
* change depending on whether an asynchronous IN pipe has been used. */
LIBUSBP_API
libusbp_error * libusbp_generic_handle_open_async_in_pipe(
libusbp_generic_handle *,
uint8_t pipe_id,
libusbp_async_in_pipe ** async_in_pipe);
/*! Sets a timeout for a particular pipe on the USB device.
*
* The @a pipe_id should either be 0 to specify control transfers on endpoint 0, or
* should be a bEndpointAddress value from one of the device's endpoint
* descriptors. Specifying an invalid pipe might result in an error.
*
* The timeout value is specified in milliseconds, and a value of 0 means no
* timeout (wait forever). If this function is not called, the default behavior
* of the handle is to have no timeout.
*
* The behavior of this function is unspecified if there is any data being
* transferred on the pipe while this function is running.
*
* It is unspecified whether this timeout has an effect on asynchronous
* transfers. */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_generic_handle_set_timeout(
libusbp_generic_handle *,
uint8_t pipe_id,
uint32_t timeout);
/*! Performs a synchronous (blocking) control transfer on endpoint 0.
*
* Under Linux, this blocking transfer unfortunately cannot be interrupted with
* Ctrl+C.
*
* The @a buffer parameter should point to a buffer that is at least @a wLength
* bytes long.
*
* The @a transferred pointer is optional, and is used to return the number of
* bytes that were actually transferred.
*
* The direction of the transfer is determined by the @a bmRequestType parameter.
*/
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_control_transfer(
libusbp_generic_handle *,
uint8_t bmRequestType,
uint8_t bRequest,
uint16_t wValue,
uint16_t wIndex,
void * buffer,
uint16_t wLength,
size_t * transferred);
/*! Performs a synchronous (blocking) write of data to a bulk or interrupt
* endpoint.
*
* Under Linux, this blocking transfer unfortunately cannot be interrupted with
* Ctrl+C.
*
* The @a pipe_id parameter specifies which endpoint to use. This argument
* should be bEndpointAddress value from one of the device's IN endpoint
* descriptors. (Its most significant bit must be 0.)
*
* The @a transferred parameter is an optional pointer to a variable that will
* receive the number of bytes transferred. */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_write_pipe(
libusbp_generic_handle *,
uint8_t pipe_id,
const void * buffer,
size_t size,
size_t * transferred);
/*! Performs a synchronous (blocking) read of data from a bulk or interrupt
* endpoint.
*
* It is best to set the buffer size to a multiple of the maximum
* packet size of the endpoint. Otherwise, this function might return
* an error when the device sends more data than can fit in the
* buffer. This type of error is called an overflow.
*
* Under Linux, this blocking transfer unfortunately cannot be interrupted with
* Ctrl+C.
*
* The @a pipe_id parameter specifies which endpoint to use. This argument
* should be bEndpointAddress value from one of the device's IN endpoint
* descriptors. (Its most significant bit must be 1.)
*
* The @a transferred parameter is an optional pointer to a variable that will
* receive the number of bytes transferred. */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_read_pipe(
libusbp_generic_handle *,
uint8_t pipe_id,
void * buffer,
size_t size,
size_t * transferred);
#ifdef __linux__
/*! Gets the underlying file descriptor of the generic handle. This function is
* only available on Linux, and is intended for advanced users. The returned
* file descriptor will remain open and valid as long as the handle is open and
* has not been closed. */
LIBUSBP_API
int libusbp_generic_handle_get_fd(libusbp_generic_handle *);
#endif
#ifdef _WIN32
/*! Gets the underlying WinUSB handle for the generic handle. This function is
* only available on Windows, and is intended for advanced users. The returned
* WinUSB handle will remain open and valid as long as the generic handle is
* open and has not been closed. */
LIBUSBP_API
HANDLE libusbp_generic_handle_get_winusb_handle(libusbp_generic_handle *);
#endif
#ifdef __APPLE__
/*! Gets the underlying IOCFPlugInInterface object representing the interface.
* You can cast the returned pointer to a `IOCFPlugInInterface **` and then use
* `QueryInterface` to get the corresponding `IOUSBInterfaceInterface **`.
* There is an example of this in generic_handle_test.cpp. */
LIBUSBP_API
void ** libusbp_generic_handle_get_cf_plug_in(libusbp_generic_handle *);
#endif
/** libusbp_serial_port ********************************************************/
/*! Represents a serial port. A null libusbp_serial_port pointer is valid and
* can be passed to any function in this library that takes such pointers. */
typedef struct libusbp_serial_port
libusbp_serial_port;
/*! Creates a serial port object for a specified interface of the
* specified USB device.
*
* On all platforms, if a record of the interface cannot be found, then an error
* is returned with the code LIBUSBP_ERROR_NOT_READY, because this could just be
* a temporary condition that happens right after the device is plugged in.
*
* On macOS, it is assumed that the interface with a @a bInterfaceNumber one
* greater than @a interface_number is the interface that the IOSerialBSDClient
* will attach to. This should be true if the device implements the USB CDC ACM
* class and has ordered its interfaces so that the control interface is right
* before the data interface.
*
* @param interface_number The lowest @a bInterfaceNumber for the USB interfaces
* that comprise the serial port.
*
* @param composite Should be true if the device is composite, and false
* otherwise.
*
* The returned object must be freed with libusbp_generic_interface_free(). */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_serial_port_create(
const libusbp_device *,
uint8_t interface_number,
bool composite,
libusbp_serial_port **);
/*! Frees the specified serial port object. Passing the NULL pointer to
* this function is OK. Do not free the same non-NULL pointer twice. */
LIBUSBP_API void libusbp_serial_port_free(libusbp_serial_port *);
/*! Makes a copy of the generic interface object. The copy must be freed with
* libusbp_generic_interface_free(). */
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_serial_port_copy(
const libusbp_serial_port * source,
libusbp_serial_port ** dest);
/*! Gets the user-friendly name of the COM port
* that could be used to open a handle.
*
* On Windows, this will be something like "COM12".
*
* On Linux, it will be something like "/dev/ttyACM0".
*
* On macOS, it will be something like "/dev/cu.usbmodem012345".
* Specifically, it will be a call-out device, not a dial-in device.
*
* You should free the returned string by calling libusbp_string_free().
*/
LIBUSBP_API LIBUSBP_WARN_UNUSED
libusbp_error * libusbp_serial_port_get_name(
const libusbp_serial_port *,
char ** name);
#ifdef __cplusplus
}
#endif