271ff3fa1d
Co-authored-by: Zachary Levy <zachary@sunforge.is> Reviewed-on: #37
1716 lines
69 KiB
Odin
1716 lines
69 KiB
Odin
package libusb
|
|
|
|
import "core:c"
|
|
|
|
// =============================================================================
|
|
// Foreign import — platform-selected linking
|
|
// =============================================================================
|
|
|
|
// Set to false to statically link libusb on Windows.
|
|
// On Linux/macOS, the system linker decides static vs dynamic based on what's
|
|
// available; use pkg-config or linker flags to control it externally.
|
|
LIBUSB_SHARED :: #config(LIBUSB_SHARED, true)
|
|
|
|
//odinfmt: disable
|
|
when ODIN_OS == .Windows {
|
|
when ODIN_ARCH == .amd64 {
|
|
when LIBUSB_SHARED {
|
|
foreign import lib "windows-x64/libusb-1.0.lib"
|
|
} else {
|
|
foreign import lib {
|
|
"windows-x64/libusb-1.0-static.lib",
|
|
"system:Advapi32.lib",
|
|
"system:Ole32.lib",
|
|
"system:Setupapi.lib",
|
|
}
|
|
}
|
|
} else when ODIN_ARCH == .i386 {
|
|
when LIBUSB_SHARED {
|
|
foreign import lib "windows-x86/libusb-1.0.lib"
|
|
} else {
|
|
foreign import lib {
|
|
"windows-x86/libusb-1.0-static.lib",
|
|
"system:Advapi32.lib",
|
|
"system:Ole32.lib",
|
|
"system:Setupapi.lib",
|
|
}
|
|
}
|
|
} else {
|
|
#panic("Unsupported Windows architecture for libusb. Only amd64 and i386 are supported.")
|
|
}
|
|
} else {
|
|
// Linux, macOS, BSD — link against system-installed libusb.
|
|
// Install via: apt install libusb-1.0-0-dev / brew install libusb / etc.
|
|
foreign import lib "system:usb-1.0"
|
|
}
|
|
//odinfmt: enable
|
|
|
|
// libusb API version (1.0.30).
|
|
API_VERSION :: 0x0100010C
|
|
|
|
// Descriptor sizes per descriptor type.
|
|
DT_DEVICE_SIZE :: 18
|
|
DT_CONFIG_SIZE :: 9
|
|
DT_INTERFACE_SIZE :: 9
|
|
DT_INTERFACE_ASSOCIATION_SIZE :: 8
|
|
DT_ENDPOINT_SIZE :: 7
|
|
DT_ENDPOINT_AUDIO_SIZE :: 9
|
|
DT_HUB_NONVAR_SIZE :: 7
|
|
DT_SS_ENDPOINT_COMPANION_SIZE :: 6
|
|
DT_BOS_SIZE :: 5
|
|
DT_DEVICE_CAPABILITY_SIZE :: 3
|
|
|
|
// BOS descriptor sizes.
|
|
BT_USB_2_0_EXTENSION_SIZE :: 7
|
|
BT_SS_USB_DEVICE_CAPABILITY_SIZE :: 10
|
|
BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE :: 12
|
|
BT_CONTAINER_ID_SIZE :: 20
|
|
BT_PLATFORM_DESCRIPTOR_MIN_SIZE :: 20
|
|
|
|
// Maximum BOS descriptor size (sum of all sub-descriptors).
|
|
DT_BOS_MAX_SIZE ::
|
|
DT_BOS_SIZE + BT_USB_2_0_EXTENSION_SIZE + BT_SS_USB_DEVICE_CAPABILITY_SIZE + BT_CONTAINER_ID_SIZE
|
|
|
|
// Endpoint address / direction masks.
|
|
ENDPOINT_ADDRESS_MASK :: 0x0f
|
|
ENDPOINT_DIR_MASK :: 0x80
|
|
|
|
// Transfer type mask in bmAttributes.
|
|
TRANSFER_TYPE_MASK :: 0x03
|
|
|
|
// Iso sync type mask in bmAttributes.
|
|
ISO_SYNC_TYPE_MASK :: 0x0c
|
|
|
|
// Iso usage type mask in bmAttributes.
|
|
ISO_USAGE_TYPE_MASK :: 0x30
|
|
|
|
// Control setup packet size (8 bytes).
|
|
CONTROL_SETUP_SIZE :: 8
|
|
|
|
// Total number of error codes in the Error enum.
|
|
ERROR_COUNT :: 14
|
|
|
|
// Hotplug convenience constants.
|
|
HOTPLUG_NO_FLAGS :: Hotplug_Flags{}
|
|
HOTPLUG_MATCH_ANY :: c.int(-1)
|
|
|
|
// Maximum length for a device string descriptor in UTF-8 (libusb 1.0.30+).
|
|
DEVICE_STRING_BYTES_MAX :: 384
|
|
|
|
// Poll event constants matching <poll.h> values.
|
|
POLLIN :: c.short(0x0001)
|
|
POLLPRI :: c.short(0x0002)
|
|
POLLOUT :: c.short(0x0004)
|
|
POLLERR :: c.short(0x0008)
|
|
POLLHUP :: c.short(0x0010)
|
|
|
|
// Device and/or Interface Class codes.
|
|
Class_Code :: enum c.int {
|
|
// In the context of a device descriptor, this bDeviceClass value indicates
|
|
// that each interface specifies its own class information and all interfaces
|
|
// operate independently.
|
|
PER_INTERFACE = 0x00,
|
|
// Audio class.
|
|
AUDIO = 0x01,
|
|
// Communications class.
|
|
COMM = 0x02,
|
|
// Human Interface Device class.
|
|
HID = 0x03,
|
|
// Physical.
|
|
PHYSICAL = 0x05,
|
|
// Image class.
|
|
IMAGE = 0x06,
|
|
// Printer class.
|
|
PRINTER = 0x07,
|
|
// Mass storage class.
|
|
MASS_STORAGE = 0x08,
|
|
// Hub class.
|
|
HUB = 0x09,
|
|
// Data class.
|
|
DATA = 0x0a,
|
|
// Smart Card.
|
|
SMART_CARD = 0x0b,
|
|
// Content Security.
|
|
CONTENT_SECURITY = 0x0d,
|
|
// Video.
|
|
VIDEO = 0x0e,
|
|
// Personal Healthcare.
|
|
PERSONAL_HEALTHCARE = 0x0f,
|
|
// Audio & Video.
|
|
AUDIO_VIDEO = 0x10,
|
|
// Billboard.
|
|
BILLBOARD = 0x11,
|
|
// USB Type-C Bridge class.
|
|
TYPE_C_BRIDGE = 0x12,
|
|
// Bulk Display Protocol.
|
|
BULK_DISPLAY = 0x13,
|
|
// Management Component Transport Protocol.
|
|
MCTP = 0x14,
|
|
// I3C class.
|
|
I3C = 0x3c,
|
|
// Diagnostic Device.
|
|
DIAGNOSTIC_DEVICE = 0xdc,
|
|
// Wireless class.
|
|
WIRELESS = 0xe0,
|
|
// Miscellaneous class.
|
|
MISCELLANEOUS = 0xef,
|
|
// Application class.
|
|
APPLICATION = 0xfe,
|
|
// Class is vendor-specific.
|
|
VENDOR_SPEC = 0xff,
|
|
}
|
|
|
|
// Legacy alias from libusb-0.1.
|
|
CLASS_PTP :: Class_Code.IMAGE
|
|
|
|
// Descriptor types as defined by the USB specification.
|
|
Descriptor_Type :: enum c.int {
|
|
// Device descriptor. See `Device_Descriptor`.
|
|
DEVICE = 0x01,
|
|
// Configuration descriptor. See `Config_Descriptor`.
|
|
CONFIG = 0x02,
|
|
// String descriptor.
|
|
STRING = 0x03,
|
|
// Interface descriptor. See `Interface_Descriptor`.
|
|
INTERFACE = 0x04,
|
|
// Endpoint descriptor. See `Endpoint_Descriptor`.
|
|
ENDPOINT = 0x05,
|
|
// Interface Association Descriptor. See `Interface_Association_Descriptor`.
|
|
INTERFACE_ASSOCIATION = 0x0b,
|
|
// BOS descriptor.
|
|
BOS = 0x0f,
|
|
// Device Capability descriptor.
|
|
DEVICE_CAPABILITY = 0x10,
|
|
// HID descriptor.
|
|
HID = 0x21,
|
|
// HID report descriptor.
|
|
REPORT = 0x22,
|
|
// Physical descriptor.
|
|
PHYSICAL = 0x23,
|
|
// Hub descriptor.
|
|
HUB = 0x29,
|
|
// SuperSpeed Hub descriptor.
|
|
SUPERSPEED_HUB = 0x2a,
|
|
// SuperSpeed Endpoint Companion descriptor.
|
|
SS_ENDPOINT_COMPANION = 0x30,
|
|
}
|
|
|
|
// Endpoint direction. Values for bit 7 of the endpoint address.
|
|
Endpoint_Direction :: enum c.int {
|
|
// Out: host-to-device.
|
|
OUT = 0x00,
|
|
// In: device-to-host.
|
|
IN = 0x80,
|
|
}
|
|
|
|
// Endpoint transfer type. Values for bits 0:1 of bmAttributes.
|
|
Endpoint_Transfer_Type :: enum c.int {
|
|
// Control endpoint.
|
|
CONTROL = 0x0,
|
|
// Isochronous endpoint.
|
|
ISOCHRONOUS = 0x1,
|
|
// Bulk endpoint.
|
|
BULK = 0x2,
|
|
// Interrupt endpoint.
|
|
INTERRUPT = 0x3,
|
|
}
|
|
|
|
// Standard requests, as defined in table 9-5 of the USB 3.0 specifications.
|
|
Standard_Request :: enum c.int {
|
|
// Request status of the specific recipient.
|
|
GET_STATUS = 0x00,
|
|
// Clear or disable a specific feature.
|
|
CLEAR_FEATURE = 0x01,
|
|
// Set or enable a specific feature. (0x02 is reserved.)
|
|
SET_FEATURE = 0x03,
|
|
// Set device address for all future accesses. (0x04 is reserved.)
|
|
SET_ADDRESS = 0x05,
|
|
// Get the specified descriptor.
|
|
GET_DESCRIPTOR = 0x06,
|
|
// Used to update existing descriptors or add new descriptors.
|
|
SET_DESCRIPTOR = 0x07,
|
|
// Get the current device configuration value.
|
|
GET_CONFIGURATION = 0x08,
|
|
// Set device configuration.
|
|
SET_CONFIGURATION = 0x09,
|
|
// Return the selected alternate setting for the specified interface.
|
|
GET_INTERFACE = 0x0a,
|
|
// Select an alternate interface for the specified interface.
|
|
SET_INTERFACE = 0x0b,
|
|
// Set then report an endpoint's synchronization frame.
|
|
SYNCH_FRAME = 0x0c,
|
|
// Sets both the U1 and U2 Exit Latency.
|
|
SET_SEL = 0x30,
|
|
// Delay from the time a host transmits a packet to the time it is
|
|
// received by the device.
|
|
SET_ISOCH_DELAY = 0x31,
|
|
}
|
|
|
|
// Request type bits of the bmRequestType field in control transfers.
|
|
Request_Type :: enum c.int {
|
|
// Standard.
|
|
STANDARD = 0x00 << 5,
|
|
// Class.
|
|
CLASS = 0x01 << 5,
|
|
// Vendor.
|
|
VENDOR = 0x02 << 5,
|
|
// Reserved.
|
|
RESERVED = 0x03 << 5,
|
|
}
|
|
|
|
// Recipient bits of the bmRequestType field in control transfers.
|
|
// Values 4 through 31 are reserved.
|
|
Request_Recipient :: enum c.int {
|
|
// Device.
|
|
DEVICE = 0x00,
|
|
// Interface.
|
|
INTERFACE = 0x01,
|
|
// Endpoint.
|
|
ENDPOINT = 0x02,
|
|
// Other.
|
|
OTHER = 0x03,
|
|
}
|
|
|
|
// Synchronization type for isochronous endpoints.
|
|
// Values for bits 2:3 of bmAttributes.
|
|
Iso_Sync_Type :: enum c.int {
|
|
// No synchronization.
|
|
NONE = 0x0,
|
|
// Asynchronous.
|
|
ASYNC = 0x1,
|
|
// Adaptive.
|
|
ADAPTIVE = 0x2,
|
|
// Synchronous.
|
|
SYNC = 0x3,
|
|
}
|
|
|
|
// Usage type for isochronous endpoints.
|
|
// Values for bits 4:5 of bmAttributes.
|
|
Iso_Usage_Type :: enum c.int {
|
|
// Data endpoint.
|
|
DATA = 0x0,
|
|
// Feedback endpoint.
|
|
FEEDBACK = 0x1,
|
|
// Implicit feedback data endpoint.
|
|
IMPLICIT = 0x2,
|
|
}
|
|
|
|
// Supported speeds (wSpeedSupported) — bitmask flags.
|
|
// Indicates what speeds the device supports.
|
|
Supported_Speed_Bit :: enum u16 {
|
|
// Low speed operation supported (1.5MBit/s).
|
|
LOW = 0,
|
|
// Full speed operation supported (12MBit/s).
|
|
FULL = 1,
|
|
// High speed operation supported (480MBit/s).
|
|
HIGH = 2,
|
|
// Superspeed operation supported (5000MBit/s).
|
|
SUPER = 3,
|
|
}
|
|
Supported_Speeds :: bit_set[Supported_Speed_Bit;u16]
|
|
|
|
// Masks for the bits of the bmAttributes field of the USB 2.0 Extension
|
|
// descriptor.
|
|
Usb2_Ext_Attribute_Bit :: enum u32 {
|
|
// Supports Link Power Management (LPM).
|
|
LPM_SUPPORT = 1,
|
|
}
|
|
Usb2_Ext_Attributes :: bit_set[Usb2_Ext_Attribute_Bit;u32]
|
|
|
|
// Masks for the bits of the bmAttributes field of the SuperSpeed USB Device
|
|
// Capability descriptor.
|
|
Ss_Dev_Cap_Attribute_Bit :: enum u8 {
|
|
// Supports Latency Tolerance Messages (LTM).
|
|
LTM_SUPPORT = 1,
|
|
}
|
|
Ss_Dev_Cap_Attributes :: bit_set[Ss_Dev_Cap_Attribute_Bit;u8]
|
|
|
|
// USB capability types (BOS).
|
|
Bos_Type :: enum c.int {
|
|
// Wireless USB device capability.
|
|
WIRELESS_USB_DEVICE_CAPABILITY = 0x01,
|
|
// USB 2.0 extensions.
|
|
USB_2_0_EXTENSION = 0x02,
|
|
// SuperSpeed USB device capability.
|
|
SS_USB_DEVICE_CAPABILITY = 0x03,
|
|
// Container ID type.
|
|
CONTAINER_ID = 0x04,
|
|
// Platform descriptor.
|
|
PLATFORM_DESCRIPTOR = 0x05,
|
|
// SuperSpeedPlus device capability.
|
|
SUPERSPEED_PLUS_CAPABILITY = 0x0A,
|
|
}
|
|
|
|
// Speed codes. Indicates the speed at which the device is operating.
|
|
Speed :: enum c.int {
|
|
// The OS doesn't report or know the device speed.
|
|
UNKNOWN = 0,
|
|
// The device is operating at low speed (1.5MBit/s).
|
|
LOW = 1,
|
|
// The device is operating at full speed (12MBit/s).
|
|
FULL = 2,
|
|
// The device is operating at high speed (480MBit/s).
|
|
HIGH = 3,
|
|
// The device is operating at super speed (5000MBit/s).
|
|
SUPER = 4,
|
|
// The device is operating at super speed plus (10000MBit/s).
|
|
SUPER_PLUS = 5,
|
|
// The device is operating at super speed plus x2 (20000MBit/s).
|
|
SUPER_PLUS_X2 = 6,
|
|
}
|
|
|
|
// Error codes. Most libusb functions return 0 on success or one of these
|
|
// codes on failure. Use `error_name()` for a string representation or
|
|
// `strerror()` for an end-user description.
|
|
Error :: enum c.int {
|
|
// Success (no error).
|
|
SUCCESS = 0,
|
|
// Input/output error.
|
|
IO = -1,
|
|
// Invalid parameter.
|
|
INVALID_PARAM = -2,
|
|
// Access denied (insufficient permissions).
|
|
ACCESS = -3,
|
|
// No such device (it may have been disconnected).
|
|
NO_DEVICE = -4,
|
|
// Entity not found.
|
|
NOT_FOUND = -5,
|
|
// Resource busy.
|
|
BUSY = -6,
|
|
// Operation timed out.
|
|
TIMEOUT = -7,
|
|
// Overflow.
|
|
OVERFLOW = -8,
|
|
// Pipe error.
|
|
PIPE = -9,
|
|
// System call interrupted (perhaps due to signal).
|
|
INTERRUPTED = -10,
|
|
// Insufficient memory.
|
|
NO_MEM = -11,
|
|
// Operation not supported or unimplemented on this platform.
|
|
NOT_SUPPORTED = -12,
|
|
// Other error.
|
|
OTHER = -99,
|
|
}
|
|
|
|
// Transfer type (for the Transfer struct's `type` field).
|
|
// Stored as u8 to match libusb_transfer.type which is `unsigned char`.
|
|
Transfer_Type :: enum u8 {
|
|
// Control transfer.
|
|
CONTROL = 0,
|
|
// Isochronous transfer.
|
|
ISOCHRONOUS = 1,
|
|
// Bulk transfer.
|
|
BULK = 2,
|
|
// Interrupt transfer.
|
|
INTERRUPT = 3,
|
|
// Bulk stream transfer.
|
|
BULK_STREAM = 4,
|
|
}
|
|
|
|
// Transfer status codes.
|
|
Transfer_Status :: enum c.int {
|
|
// Transfer completed without error. Note that this does not indicate that
|
|
// the entire amount of requested data was transferred.
|
|
COMPLETED,
|
|
// Transfer failed.
|
|
ERROR,
|
|
// Transfer timed out.
|
|
TIMED_OUT,
|
|
// Transfer was cancelled.
|
|
CANCELLED,
|
|
// For bulk/interrupt endpoints: halt condition detected (endpoint stalled).
|
|
// For control endpoints: control request not supported.
|
|
STALL,
|
|
// Device was disconnected.
|
|
NO_DEVICE,
|
|
// Device sent more data than requested.
|
|
OVERFLOW,
|
|
}
|
|
|
|
// Transfer flag bits for use in a `Transfer_Flags` bit_set.
|
|
Transfer_Flag_Bit :: enum u8 {
|
|
// Report short frames as errors.
|
|
SHORT_NOT_OK,
|
|
// Automatically free() transfer buffer during `free_transfer()`.
|
|
// Do not use with buffers from `dev_mem_alloc()`.
|
|
FREE_BUFFER,
|
|
// Automatically call `free_transfer()` after callback returns.
|
|
// Do not call `free_transfer()` from your callback if this is set.
|
|
FREE_TRANSFER,
|
|
// Terminate transfers that are a multiple of the endpoint's
|
|
// wMaxPacketSize with an extra zero length packet. Currently
|
|
// only supported on Linux. Available since libusb-1.0.9.
|
|
ADD_ZERO_PACKET,
|
|
}
|
|
Transfer_Flags :: bit_set[Transfer_Flag_Bit;u8]
|
|
|
|
// Capabilities supported by an instance of libusb on the current running
|
|
// platform. Test with `has_capability()`.
|
|
Capability :: enum u32 {
|
|
// The `has_capability()` API is available.
|
|
HAS_CAPABILITY = 0x0000,
|
|
// Hotplug support is available on this platform.
|
|
HAS_HOTPLUG = 0x0001,
|
|
// The library can access HID devices without requiring user intervention.
|
|
// Note that before being able to actually access an HID device, you may
|
|
// still have to call additional libusb functions such as
|
|
// `detach_kernel_driver()`.
|
|
HAS_HID_ACCESS = 0x0100,
|
|
// The library supports detaching of the default USB driver, using
|
|
// `detach_kernel_driver()`, if one is set by the OS kernel.
|
|
SUPPORTS_DETACH_KERNEL_DRIVER = 0x0101,
|
|
}
|
|
|
|
// Log message levels.
|
|
Log_Level :: enum c.int {
|
|
// No messages ever emitted by the library (default).
|
|
NONE = 0,
|
|
// Error messages are emitted.
|
|
ERROR = 1,
|
|
// Warning and error messages are emitted.
|
|
WARNING = 2,
|
|
// Informational, warning and error messages are emitted.
|
|
INFO = 3,
|
|
// All messages are emitted.
|
|
DEBUG = 4,
|
|
}
|
|
|
|
// Log callback mode bits. Since version 1.0.23.
|
|
Log_Cb_Mode_Bit :: enum c.int {
|
|
// Callback function handling all log messages.
|
|
GLOBAL = 0,
|
|
// Callback function handling context related log messages.
|
|
CONTEXT = 1,
|
|
}
|
|
Log_Cb_Mode :: bit_set[Log_Cb_Mode_Bit;c.int]
|
|
|
|
// Available option values for `set_option()` and `init_context()`.
|
|
Option :: enum c.int {
|
|
// Set the log message verbosity. Argument: `Log_Level` (as c.int).
|
|
//
|
|
// The default level is NONE, which means no messages are ever printed. If
|
|
// you choose to increase the verbosity, ensure your application does not
|
|
// close the stderr file descriptor. Level WARNING is advised.
|
|
//
|
|
// If the LIBUSB_DEBUG environment variable was set when libusb was
|
|
// initialized, this option does nothing. If libusb was compiled without
|
|
// message logging, or with verbose debug logging, this option does nothing.
|
|
LOG_LEVEL = 0,
|
|
// Use the UsbDk backend for a specific context, if available.
|
|
//
|
|
// This option should be set at initialization with `init_context()`,
|
|
// otherwise unspecified behavior may occur. Only valid on Windows; ignored
|
|
// on all other platforms.
|
|
USE_USBDK = 1,
|
|
// Do not scan for devices.
|
|
//
|
|
// With this option set, libusb will skip scanning devices in
|
|
// `init_context()`, and hotplug functionality will be deactivated. Useful
|
|
// in combination with `wrap_sys_device()`, which can access a device
|
|
// directly without prior device scanning. This is typically needed on
|
|
// Android, where access to USB devices is limited.
|
|
//
|
|
// Should only be used with `init_context()`, otherwise unspecified behavior
|
|
// may occur. Only valid on Linux; ignored on all other platforms.
|
|
// Alias: WEAK_AUTHORITY.
|
|
NO_DEVICE_DISCOVERY = 2,
|
|
// Set the context log callback function, on a context or globally.
|
|
// Argument: `Log_Cb`. Using this option with a nil context is equivalent
|
|
// to calling `set_log_cb()` with mode GLOBAL; with a non-nil context, it is
|
|
// equivalent to mode CONTEXT.
|
|
LOG_CB = 3,
|
|
MAX = 4,
|
|
}
|
|
|
|
// Alias for NO_DEVICE_DISCOVERY.
|
|
OPTION_WEAK_AUTHORITY :: Option.NO_DEVICE_DISCOVERY
|
|
|
|
// Hotplug event bits. Since version 1.0.16.
|
|
Hotplug_Event_Bit :: enum c.int {
|
|
// A device has been plugged in and is ready to use.
|
|
DEVICE_ARRIVED = 0,
|
|
// A device has left and is no longer available. It is the user's
|
|
// responsibility to call `close()` on any associated handle.
|
|
DEVICE_LEFT = 1,
|
|
}
|
|
Hotplug_Events :: bit_set[Hotplug_Event_Bit;c.int]
|
|
|
|
// Hotplug flag bits. Since version 1.0.16.
|
|
Hotplug_Flag_Bit :: enum c.int {
|
|
// Arm the callback and fire it for all matching currently attached devices.
|
|
ENUMERATE = 0,
|
|
}
|
|
Hotplug_Flags :: bit_set[Hotplug_Flag_Bit;c.int]
|
|
|
|
// Device string type (libusb 1.0.30+).
|
|
Device_String_Type :: enum c.int {
|
|
MANUFACTURER,
|
|
PRODUCT,
|
|
SERIAL_NUMBER,
|
|
// The total number of string types.
|
|
COUNT,
|
|
}
|
|
|
|
// Whether a sublink speed attribute defines a symmetric or asymmetric bit
|
|
// rate (libusb 1.0.28+).
|
|
Ssplus_Sublink_Type :: enum c.int {
|
|
// Symmetric.
|
|
SYM = 0,
|
|
// Asymmetric.
|
|
ASYM = 1,
|
|
}
|
|
|
|
// Whether a sublink speed attribute defines the receive or transmit bit rate.
|
|
Ssplus_Sublink_Direction :: enum c.int {
|
|
// Receive.
|
|
RX = 0,
|
|
// Transmit.
|
|
TX = 1,
|
|
}
|
|
|
|
// Base-10 exponent (times 3) applied to the sublink mantissa.
|
|
Ssplus_Sublink_Exponent :: enum c.int {
|
|
// Bits per second.
|
|
BPS = 0,
|
|
// Kbps.
|
|
KBS = 1,
|
|
// Mbps.
|
|
MBS = 2,
|
|
// Gbps.
|
|
GBS = 3,
|
|
}
|
|
|
|
// Protocol supported by a sublink.
|
|
Ssplus_Sublink_Protocol :: enum c.int {
|
|
// SuperSpeed.
|
|
SS = 0,
|
|
// SuperSpeedPlus.
|
|
SSPLUS = 1,
|
|
}
|
|
|
|
// Setup packet for control transfers (8 bytes, packed).
|
|
// Use `fill_control_setup()` to populate. The 16-bit fields
|
|
// are stored in little-endian byte order on the wire.
|
|
Control_Setup :: struct #packed {
|
|
// Request type. Bits 0:4 determine recipient (`Request_Recipient`), bits
|
|
// 5:6 determine type (`Request_Type`), bit 7 determines data transfer
|
|
// direction (`Endpoint_Direction`).
|
|
bmRequestType: u8,
|
|
// Request. If the type bits of bmRequestType are STANDARD then this field
|
|
// refers to `Standard_Request`. Otherwise its use is application-specific.
|
|
bRequest: u8,
|
|
// Value. Varies according to request.
|
|
wValue: u16,
|
|
// Index. Varies according to request, typically used to pass an index or
|
|
// offset.
|
|
wIndex: u16,
|
|
// Number of bytes to transfer.
|
|
wLength: u16,
|
|
}
|
|
|
|
// Standard USB device descriptor (USB 3.0, section 9.6.1).
|
|
// All multi-byte fields in host-endian format.
|
|
Device_Descriptor :: struct {
|
|
// Size of this descriptor (in bytes).
|
|
bLength: u8,
|
|
// Descriptor type (`Descriptor_Type.DEVICE`).
|
|
bDescriptorType: u8,
|
|
// USB spec release number in BCD. 0x0200 = USB 2.0, etc.
|
|
bcdUSB: u16,
|
|
// USB-IF class code for the device. See `Class_Code`.
|
|
bDeviceClass: u8,
|
|
// USB-IF subclass code, qualified by bDeviceClass.
|
|
bDeviceSubClass: u8,
|
|
// USB-IF protocol code, qualified by class and subclass.
|
|
bDeviceProtocol: u8,
|
|
// Maximum packet size for endpoint 0.
|
|
bMaxPacketSize0: u8,
|
|
// USB-IF vendor ID.
|
|
idVendor: u16,
|
|
// USB-IF product ID.
|
|
idProduct: u16,
|
|
// Device release number in BCD.
|
|
bcdDevice: u16,
|
|
// Index of manufacturer string descriptor.
|
|
iManufacturer: u8,
|
|
// Index of product string descriptor.
|
|
iProduct: u8,
|
|
// Index of serial number string descriptor.
|
|
iSerialNumber: u8,
|
|
// Number of possible configurations.
|
|
bNumConfigurations: u8,
|
|
}
|
|
|
|
// Standard USB endpoint descriptor (USB 3.0, section 9.6.6).
|
|
// All multi-byte fields in host-endian format.
|
|
Endpoint_Descriptor :: struct {
|
|
// Size of this descriptor (in bytes).
|
|
bLength: u8,
|
|
// Descriptor type (`Descriptor_Type.ENDPOINT`).
|
|
bDescriptorType: u8,
|
|
// Endpoint address. Bits 0:3 = endpoint number, bit 7 = direction.
|
|
bEndpointAddress: u8,
|
|
// Endpoint attributes. Bits 0:1 = transfer type, 2:3 = iso sync type,
|
|
// 4:5 = iso usage type.
|
|
bmAttributes: u8,
|
|
// Maximum packet size this endpoint can send/receive.
|
|
wMaxPacketSize: u16,
|
|
// Polling interval for data transfers.
|
|
bInterval: u8,
|
|
// Audio devices only: rate of synchronization feedback.
|
|
bRefresh: u8,
|
|
// Audio devices only: address of the synch endpoint.
|
|
bSynchAddress: u8,
|
|
// Extra descriptors. Stored here if libusb encounters unknown descriptors.
|
|
extra: [^]u8,
|
|
// Length of extra descriptors in bytes.
|
|
extra_length: c.int,
|
|
}
|
|
|
|
// Standard USB interface association descriptor (USB 3.0, section 9.6.4).
|
|
// All multi-byte fields in host-endian format.
|
|
Interface_Association_Descriptor :: struct {
|
|
// Size of this descriptor (in bytes).
|
|
bLength: u8,
|
|
// Descriptor type (`Descriptor_Type.INTERFACE_ASSOCIATION`).
|
|
bDescriptorType: u8,
|
|
// Interface number of the first interface associated with this function.
|
|
bFirstInterface: u8,
|
|
// Number of contiguous interfaces associated with this function.
|
|
bInterfaceCount: u8,
|
|
// USB-IF class code for this function. A value of zero is not allowed. If
|
|
// 0xff, the function class is vendor-specific. All other values are
|
|
// reserved for assignment by the USB-IF.
|
|
bFunctionClass: u8,
|
|
// USB-IF subclass code for this function. If not 0xff, all values are
|
|
// reserved for assignment by the USB-IF.
|
|
bFunctionSubClass: u8,
|
|
// USB-IF protocol code for this function, qualified by bFunctionClass and
|
|
// bFunctionSubClass.
|
|
bFunctionProtocol: u8,
|
|
// Index of string descriptor describing this function.
|
|
iFunction: u8,
|
|
}
|
|
|
|
// Array of 0 or more interface association descriptors.
|
|
Interface_Association_Descriptor_Array :: struct {
|
|
// Array of interface association descriptors. Size determined by `length`.
|
|
iad: [^]Interface_Association_Descriptor,
|
|
// Number of interface association descriptors contained. Read-only.
|
|
length: c.int,
|
|
}
|
|
|
|
// Standard USB interface descriptor (USB 3.0, section 9.6.5).
|
|
// All multi-byte fields in host-endian format.
|
|
Interface_Descriptor :: struct {
|
|
// Size of this descriptor (in bytes).
|
|
bLength: u8,
|
|
// Descriptor type (`Descriptor_Type.INTERFACE`).
|
|
bDescriptorType: u8,
|
|
// Number of this interface.
|
|
bInterfaceNumber: u8,
|
|
// Value used to select this alternate setting for this interface.
|
|
bAlternateSetting: u8,
|
|
// Number of endpoints used by this interface (excluding the control
|
|
// endpoint).
|
|
bNumEndpoints: u8,
|
|
// USB-IF class code for this interface. See `Class_Code`.
|
|
bInterfaceClass: u8,
|
|
// USB-IF subclass code, qualified by bInterfaceClass.
|
|
bInterfaceSubClass: u8,
|
|
// USB-IF protocol code, qualified by class and subclass.
|
|
bInterfaceProtocol: u8,
|
|
// Index of string descriptor describing this interface.
|
|
iInterface: u8,
|
|
// Array of endpoint descriptors (length = bNumEndpoints).
|
|
endpoint: [^]Endpoint_Descriptor,
|
|
// Extra descriptors. Stored here if libusb encounters unknown descriptors.
|
|
extra: [^]u8,
|
|
// Length of the extra descriptors, in bytes.
|
|
extra_length: c.int,
|
|
}
|
|
|
|
// A collection of alternate settings for a particular USB interface.
|
|
Interface :: struct {
|
|
// Array of interface descriptors (length = num_altsetting).
|
|
altsetting: [^]Interface_Descriptor,
|
|
// Number of alternate settings that belong to this interface.
|
|
num_altsetting: c.int,
|
|
}
|
|
|
|
// Standard USB configuration descriptor (USB 3.0, section 9.6.3).
|
|
// All multi-byte fields in host-endian format.
|
|
Config_Descriptor :: struct {
|
|
// Size of this descriptor (in bytes).
|
|
bLength: u8,
|
|
// Descriptor type (`Descriptor_Type.CONFIG`).
|
|
bDescriptorType: u8,
|
|
// Total length of data returned for this configuration.
|
|
wTotalLength: u16,
|
|
// Number of interfaces supported by this configuration.
|
|
bNumInterfaces: u8,
|
|
// Identifier value for this configuration.
|
|
bConfigurationValue: u8,
|
|
// Index of string descriptor describing this configuration.
|
|
iConfiguration: u8,
|
|
// Configuration characteristics.
|
|
bmAttributes: u8,
|
|
// Max power consumption. Units of 2 mA (high-speed) or 8 mA (super-speed).
|
|
MaxPower: u8,
|
|
// Array of interfaces (length = bNumInterfaces).
|
|
interface: [^]Interface,
|
|
// Extra descriptors. Stored here if libusb encounters unknown descriptors.
|
|
extra: [^]u8,
|
|
// Length of the extra descriptors, in bytes.
|
|
extra_length: c.int,
|
|
}
|
|
|
|
// SuperSpeed endpoint companion descriptor (USB 3.0, section 9.6.7).
|
|
// All multi-byte fields in host-endian format.
|
|
Ss_Endpoint_Companion_Descriptor :: struct {
|
|
// Size of this descriptor (in bytes).
|
|
bLength: u8,
|
|
// Descriptor type (`Descriptor_Type.SS_ENDPOINT_COMPANION`).
|
|
bDescriptorType: u8,
|
|
// The maximum number of packets the endpoint can send or receive as part
|
|
// of a burst.
|
|
bMaxBurst: u8,
|
|
// In bulk EP: bits 4:0 represent the maximum number of streams the EP
|
|
// supports. In isochronous EP: bits 1:0 represent the Mult.
|
|
bmAttributes: u8,
|
|
// The total number of bytes this EP will transfer every service interval.
|
|
// Valid only for periodic EPs.
|
|
wBytesPerInterval: u16,
|
|
}
|
|
|
|
// Generic BOS Device Capability descriptor. Check bDevCapabilityType and
|
|
// call the matching get_*_descriptor function for a fully-typed struct.
|
|
Bos_Dev_Capability_Descriptor :: struct {
|
|
// Size of this descriptor (in bytes).
|
|
bLength: u8,
|
|
// Descriptor type (`Descriptor_Type.DEVICE_CAPABILITY`).
|
|
bDescriptorType: u8,
|
|
// Device Capability type. See `Bos_Type`.
|
|
bDevCapabilityType: u8,
|
|
// Device Capability data (bLength - 3 bytes). Flexible array member.
|
|
dev_capability_data: [0]u8,
|
|
}
|
|
|
|
// Binary Device Object Store (BOS) descriptor (USB 3.0, section 9.6.2).
|
|
// All multi-byte fields in host-endian format.
|
|
Bos_Descriptor :: struct {
|
|
// Size of this descriptor (in bytes).
|
|
bLength: u8,
|
|
// Descriptor type (`Descriptor_Type.BOS`).
|
|
bDescriptorType: u8,
|
|
// Length of this descriptor and all of its sub descriptors.
|
|
wTotalLength: u16,
|
|
// The number of separate device capability descriptors in the BOS.
|
|
bNumDeviceCaps: u8,
|
|
// Flexible array of device capability descriptor pointers.
|
|
dev_capability: [0]^Bos_Dev_Capability_Descriptor,
|
|
}
|
|
|
|
// USB 2.0 Extension descriptor (USB 3.0, section 9.6.2.1).
|
|
// All multi-byte fields in host-endian format.
|
|
Usb2_Extension_Descriptor :: struct {
|
|
// Size of this descriptor (in bytes).
|
|
bLength: u8,
|
|
// Descriptor type (`Descriptor_Type.DEVICE_CAPABILITY`).
|
|
bDescriptorType: u8,
|
|
// Capability type (`Bos_Type.USB_2_0_EXTENSION`).
|
|
bDevCapabilityType: u8,
|
|
// Bitmap of supported device level features. A value of one in a bit
|
|
// location indicates the feature is supported. See `Usb2_Ext_Attributes`.
|
|
bmAttributes: u32,
|
|
}
|
|
|
|
// SuperSpeed USB Device Capability descriptor (USB 3.0, section 9.6.2.2).
|
|
// All multi-byte fields in host-endian format.
|
|
Ss_Usb_Device_Capability_Descriptor :: struct {
|
|
// Size of this descriptor (in bytes).
|
|
bLength: u8,
|
|
// Descriptor type (`Descriptor_Type.DEVICE_CAPABILITY`).
|
|
bDescriptorType: u8,
|
|
// Capability type (`Bos_Type.SS_USB_DEVICE_CAPABILITY`).
|
|
bDevCapabilityType: u8,
|
|
// Bitmap of supported device level features. A value of one in a bit
|
|
// location indicates the feature is supported. See `Ss_Dev_Cap_Attributes`.
|
|
bmAttributes: u8,
|
|
// Bitmap of the speeds supported by this device when operating in
|
|
// SuperSpeed mode. See `Supported_Speeds`.
|
|
wSpeedSupported: u16,
|
|
// The lowest speed at which all the functionality supported by the device
|
|
// is available to the user.
|
|
bFunctionalitySupport: u8,
|
|
// U1 Device Exit Latency.
|
|
bU1DevExitLat: u8,
|
|
// U2 Device Exit Latency.
|
|
bU2DevExitLat: u16,
|
|
}
|
|
|
|
// Container ID descriptor (USB 3.0, section 9.6.2.3).
|
|
// All multi-byte fields, except UUIDs, in host-endian format.
|
|
Container_Id_Descriptor :: struct {
|
|
// Size of this descriptor (in bytes).
|
|
bLength: u8,
|
|
// Descriptor type (`Descriptor_Type.DEVICE_CAPABILITY`).
|
|
bDescriptorType: u8,
|
|
// Capability type (`Bos_Type.CONTAINER_ID`).
|
|
bDevCapabilityType: u8,
|
|
// Reserved field.
|
|
bReserved: u8,
|
|
// 128-bit UUID as a byte array.
|
|
ContainerID: [16]u8,
|
|
}
|
|
|
|
// Platform descriptor (USB 3.2, section 9.6.2.4).
|
|
// Contains a flexible array member — all memory must be managed manually.
|
|
Platform_Descriptor :: struct {
|
|
// Size of this descriptor (in bytes).
|
|
bLength: u8,
|
|
// Descriptor type (`Descriptor_Type.DEVICE_CAPABILITY`).
|
|
bDescriptorType: u8,
|
|
// Capability type (`Bos_Type.PLATFORM_DESCRIPTOR`).
|
|
bDevCapabilityType: u8,
|
|
// Reserved field.
|
|
bReserved: u8,
|
|
// 128-bit UUID as a byte array.
|
|
PlatformCapabilityUUID: [16]u8,
|
|
// Capability data (bLength - 20 bytes). Flexible array member.
|
|
CapabilityData: [0]u8,
|
|
}
|
|
|
|
// SuperSpeedPlus sublink attribute (libusb 1.0.28+, USB 3.1, section 9.6.2.5).
|
|
Ssplus_Sublink_Attribute :: struct {
|
|
// Sublink Speed Attribute ID (SSID). Uniquely identifies the speed of this
|
|
// sublink.
|
|
ssid: u8,
|
|
// Base-10 exponent (times 3) applied to the mantissa.
|
|
exponent: Ssplus_Sublink_Exponent,
|
|
// Whether the attribute defines a symmetric or asymmetric bit rate.
|
|
type: Ssplus_Sublink_Type,
|
|
// Whether the attribute defines the receive or transmit bit rate.
|
|
direction: Ssplus_Sublink_Direction,
|
|
// The protocol supported by the link.
|
|
protocol: Ssplus_Sublink_Protocol,
|
|
// Mantissa applied to the exponent when calculating the maximum bit rate.
|
|
mantissa: u16,
|
|
}
|
|
|
|
// SuperSpeedPlus USB Device Capability descriptor (libusb 1.0.28+).
|
|
// This is a parsed/computed representation, not the raw USB descriptor.
|
|
Ssplus_Usb_Device_Capability_Descriptor :: struct {
|
|
// Sublink Speed Attribute Count.
|
|
numSublinkSpeedAttributes: u8,
|
|
// Sublink Speed ID Count.
|
|
numSublinkSpeedIDs: u8,
|
|
// Unique ID to indicate the minimum lane speed.
|
|
ssid: u8,
|
|
// Minimum receive lane count.
|
|
minRxLaneCount: u8,
|
|
// Minimum transmit lane count.
|
|
minTxLaneCount: u8,
|
|
// Flexible array of sublink attributes (length = numSublinkSpeedAttributes).
|
|
sublinkSpeedAttributes: [0]Ssplus_Sublink_Attribute,
|
|
}
|
|
|
|
// Version of the libusb runtime.
|
|
Version :: struct {
|
|
// Library major version.
|
|
major: u16,
|
|
// Library minor version.
|
|
minor: u16,
|
|
// Library micro version.
|
|
micro: u16,
|
|
// Library nano version. Deprecated since 1.0.31: this value is frozen and
|
|
// no longer updated per build. Use `describe` for a unique-per-build
|
|
// identifier.
|
|
nano: u16,
|
|
// Library release candidate suffix string, e.g. "-rc4".
|
|
rc: cstring,
|
|
// Human-readable build identifier (never nil). Intended for display, logs,
|
|
// and bug reports; the overall format is not stable, do not parse.
|
|
describe: cstring,
|
|
}
|
|
|
|
// Isochronous packet descriptor.
|
|
Iso_Packet_Descriptor :: struct {
|
|
// Length of data to request in this packet.
|
|
length: c.uint,
|
|
// Amount of data that was actually transferred.
|
|
actual_length: c.uint,
|
|
// Status code for this packet.
|
|
status: Transfer_Status,
|
|
}
|
|
|
|
// Generic USB transfer structure.
|
|
Transfer :: struct {
|
|
// Handle of the device that this transfer will be submitted to.
|
|
dev_handle: Device_Handle,
|
|
// Bitwise OR of `Transfer_Flags`.
|
|
flags: Transfer_Flags,
|
|
// Address of the endpoint where this transfer will be sent.
|
|
endpoint: u8,
|
|
// Type of the transfer from `Transfer_Type`.
|
|
type: Transfer_Type,
|
|
// Timeout for this transfer in milliseconds. 0 = no timeout.
|
|
timeout: c.uint,
|
|
// Status of the transfer. Read-only, valid only within the callback.
|
|
status: Transfer_Status,
|
|
// Length of the data buffer.
|
|
length: c.int,
|
|
// Actual length of data transferred. Read-only, valid only within callback.
|
|
actual_length: c.int,
|
|
// Callback invoked when the transfer completes, fails, or is cancelled.
|
|
callback: Transfer_Cb,
|
|
// User context data accessible from within the callback.
|
|
user_data: rawptr,
|
|
// Data buffer.
|
|
buffer: [^]u8,
|
|
// Number of isochronous packets. Only for isochronous endpoints.
|
|
num_iso_packets: c.int,
|
|
// Isochronous packet descriptors. Flexible array member.
|
|
iso_packet_desc: [0]Iso_Packet_Descriptor,
|
|
}
|
|
|
|
// Platform-specific timeval struct matching the system's struct timeval.
|
|
// libusb uses this for event-loop timeouts.
|
|
when ODIN_OS == .Darwin {
|
|
Timeval :: struct {
|
|
tv_sec: c.long,
|
|
tv_usec: i32,
|
|
}
|
|
} else {
|
|
Timeval :: struct {
|
|
tv_sec: c.long,
|
|
tv_usec: c.long,
|
|
}
|
|
}
|
|
|
|
// File descriptor for polling.
|
|
Poll_Fd :: struct {
|
|
fd: c.int,
|
|
// Event flags from <poll.h>. POLLIN for read-ready, POLLOUT for write-ready.
|
|
events: c.short,
|
|
}
|
|
|
|
// Option value union for `Init_Option`.
|
|
Init_Option_Value :: struct #raw_union {
|
|
// An integer value used by the option (if applicable).
|
|
ival: c.int,
|
|
// A log callback value used by the option (if applicable).
|
|
log_cb: Log_Cb,
|
|
}
|
|
|
|
// Option structure for `init_context()`.
|
|
Init_Option :: struct {
|
|
// Which option to set.
|
|
option: Option,
|
|
// The value to set the option to (if the option takes one).
|
|
value: Init_Option_Value,
|
|
}
|
|
|
|
//----- Opaque handles ----------------------------------
|
|
|
|
Context :: distinct rawptr
|
|
Device :: distinct rawptr
|
|
Device_Handle :: distinct rawptr
|
|
|
|
// Hotplug callback handle, returned by `hotplug_register_callback()`.
|
|
Callback_Handle :: distinct c.int
|
|
|
|
//----- Callback types ----------------------------------
|
|
|
|
// Asynchronous transfer callback. When submitting asynchronous transfers, you
|
|
// pass a pointer to a callback of this type via the `callback` member of the
|
|
// `Transfer`. libusb calls this later, when the transfer has completed or
|
|
// failed.
|
|
Transfer_Cb :: #type proc "c" (transfer: ^Transfer)
|
|
|
|
// Callback function for handling log messages. `ctx` is the context related to
|
|
// the message, or nil for a global message. `level` is the log level and `str`
|
|
// is the message. Since version 1.0.23.
|
|
Log_Cb :: #type proc "c" (ctx: Context, level: Log_Level, str: cstring)
|
|
|
|
// Hotplug event callback. When requesting hotplug notifications, you pass a
|
|
// pointer to a callback of this type. It may be called by an internal event
|
|
// thread, so it is recommended to do minimal processing before returning. It
|
|
// is safe to call `hotplug_register_callback()` or
|
|
// `hotplug_deregister_callback()` from within the callback. Return true to
|
|
// indicate this callback is finished processing events (deregistering it).
|
|
// Since version 1.0.16.
|
|
Hotplug_Callback_Fn :: #type proc "c" (
|
|
ctx: Context,
|
|
device: Device,
|
|
event: Hotplug_Events,
|
|
user_data: rawptr,
|
|
) -> b32
|
|
|
|
// Callback invoked when a new file descriptor should be added to the set of
|
|
// file descriptors monitored for events.
|
|
Pollfd_Added_Cb :: #type proc "c" (fd: c.int, events: c.short, user_data: rawptr)
|
|
|
|
// Callback invoked when a file descriptor should be removed from the set being
|
|
// monitored for events. After returning, do not use that file descriptor again.
|
|
Pollfd_Removed_Cb :: #type proc "c" (fd: c.int, user_data: rawptr)
|
|
|
|
@(default_calling_convention = "c", link_prefix = "libusb_")
|
|
foreign lib {
|
|
|
|
// ---- Library initialization/deinitialization ----
|
|
|
|
// Set the log handler. libusb redirects its log messages to `cb`. Per-context
|
|
// and global messages are supported; context messages also go to the global
|
|
// handler. `ctx` may be nil for the default context (ignored when only the
|
|
// GLOBAL mode is requested). Pass a nil `cb` to stop redirection.
|
|
// Since version 1.0.23.
|
|
set_log_cb :: proc(ctx: Context, cb: Log_Cb, mode: Log_Cb_Mode) ---
|
|
// Set an option in the library. Some options require arguments; consult each
|
|
// `Option`. If `ctx` is nil, the option is added to a list of defaults
|
|
// applied to all subsequently created contexts. Returns SUCCESS, or
|
|
// INVALID_PARAM / NOT_SUPPORTED / NOT_FOUND. Since version 1.0.22.
|
|
set_option :: proc(ctx: Context, option: Option, #c_vararg args: ..any) -> Error ---
|
|
// Deprecated initialization function, equivalent to `init_context(ctx, nil, 0)`.
|
|
// Must be called before any other libusb function. If `ctx` is nil, a default
|
|
// context is created (or reused).
|
|
init :: proc(ctx: ^Context) -> Error ---
|
|
// Initialize libusb. Must be called before any other libusb function. If you
|
|
// do not provide an output location for a context pointer, a default context
|
|
// is created (and reused if one already exists). If `num_options` is 0 then
|
|
// `options` is ignored and may be nil. Returns SUCCESS or an Error.
|
|
// Since version 1.0.27.
|
|
init_context :: proc(ctx: ^Context, options: [^]Init_Option, num_options: c.int) -> Error ---
|
|
// Deinitialize libusb. Should be called after closing all open devices and
|
|
// before your application terminates. `ctx` may be nil for the default context.
|
|
exit :: proc(ctx: Context) ---
|
|
|
|
// Deprecated: use `set_option(.LOG_LEVEL, level)` instead.
|
|
set_debug :: proc(ctx: Context, level: c.int) ---
|
|
|
|
// ---- Device handling and enumeration ----
|
|
|
|
// Returns a list of USB devices currently attached to the system. You must
|
|
// later free the list with `free_device_list()` (which can optionally unref
|
|
// the devices). Be careful not to unref a device you are about to open until
|
|
// after you have opened it. Returns the number of devices in the list (the
|
|
// list is NULL-terminated, so it is actually one element larger), or a
|
|
// negative Error code.
|
|
get_device_list :: proc(ctx: Context, list: ^[^]Device) -> int ---
|
|
// Free a list of devices obtained from `get_device_list()`. If `unref_devices`
|
|
// is true, the reference count of each device in the list is decremented by 1.
|
|
free_device_list :: proc(list: [^]Device, unref_devices: b32) ---
|
|
// Get the number of the bus that a device is connected to.
|
|
get_bus_number :: proc(dev: Device) -> u8 ---
|
|
// Get the number of the port that a device is connected to. Usually uniquely
|
|
// tied to a physical port. Returns 0 if not available.
|
|
get_port_number :: proc(dev: Device) -> u8 ---
|
|
// Get the list of all port numbers from root for the specified device.
|
|
// `port_numbers_len` is the max length of the array (max depth is 7 per the
|
|
// USB 3.0 spec). Returns the number of elements filled, or OVERFLOW if the
|
|
// array is too small. Since version 1.0.16.
|
|
get_port_numbers :: proc(dev: Device, port_numbers: [^]u8, port_numbers_len: c.int) -> c.int ---
|
|
// Deprecated: use `get_port_numbers()` instead.
|
|
get_port_path :: proc(ctx: Context, dev: Device, path: [^]u8, path_length: u8) -> c.int ---
|
|
// Get the parent of the specified device. Returns the parent, or nil if not
|
|
// available. Only valid between a `get_device_list()` / `free_device_list()`
|
|
// pair.
|
|
get_parent :: proc(dev: Device) -> Device ---
|
|
// Get the address of the device on the bus it is connected to.
|
|
get_device_address :: proc(dev: Device) -> u8 ---
|
|
// Get the negotiated connection speed for a device. Returns a `Speed` code;
|
|
// UNKNOWN means the OS doesn't know or doesn't support reporting it.
|
|
get_device_speed :: proc(dev: Device) -> Speed ---
|
|
// Returns the backend-specific identifier of the underlying system device
|
|
// tree node. Since version 1.0.30.
|
|
get_session_data :: proc(dev: Device) -> c.ulong ---
|
|
// Convenience function to retrieve the wMaxPacketSize value for an endpoint
|
|
// in the active device configuration. Returns the wMaxPacketSize value, or
|
|
// NOT_FOUND / OTHER. For iso transfers prefer `get_max_iso_packet_size()`.
|
|
get_max_packet_size :: proc(dev: Device, endpoint: u8) -> c.int ---
|
|
// Calculate the maximum packet size an endpoint is capable of sending or
|
|
// receiving in 1 microframe. Useful when setting up isochronous transfers.
|
|
// Returns the max packet size, or NOT_FOUND / OTHER.
|
|
get_max_iso_packet_size :: proc(dev: Device, endpoint: u8) -> c.int ---
|
|
// Like `get_max_iso_packet_size()` but for a specific interface and alternate
|
|
// setting rather than the first one. Since version 1.0.27.
|
|
get_max_alt_packet_size :: proc(dev: Device, interface_number: c.int, alternate_setting: c.int, endpoint: u8) -> c.int ---
|
|
// Increment the reference count of a device. Returns the same device.
|
|
ref_device :: proc(dev: Device) -> Device ---
|
|
// Decrement the reference count of a device. The device is destroyed when its
|
|
// reference count reaches 0.
|
|
unref_device :: proc(dev: Device) ---
|
|
// Wrap a platform-specific system device handle to obtain a libusb device
|
|
// handle. On Linux, `sys_dev` must be a valid file descriptor opened on the
|
|
// device node. The system handle must remain open until `close()` and is not
|
|
// closed by `close()`. Since version 1.0.23.
|
|
wrap_sys_device :: proc(ctx: Context, sys_dev: c.intptr_t, dev_handle: ^Device_Handle) -> Error ---
|
|
// Open a device and obtain a device handle, which allows you to perform I/O.
|
|
// Adds a reference to the device (removed by `close()`). Returns SUCCESS, or
|
|
// NO_MEM / ACCESS / NO_DEVICE.
|
|
open :: proc(dev: Device, dev_handle: ^Device_Handle) -> Error ---
|
|
// Convenience function to open the first device with the given vendor/product
|
|
// IDs. Not intended for real applications (e.g. it only returns the first
|
|
// match). Returns a device handle, or nil on error / if not found.
|
|
open_device_with_vid_pid :: proc(ctx: Context, vendor_id: u16, product_id: u16) -> Device_Handle ---
|
|
// Close a device handle. Should be called on all open handles before your
|
|
// application exits. Destroys the reference added by `open()`.
|
|
close :: proc(dev_handle: Device_Handle) ---
|
|
// Get the underlying device for a device handle. Does not modify the device's
|
|
// reference count, so you need not unref the result.
|
|
get_device :: proc(dev_handle: Device_Handle) -> Device ---
|
|
// Determine the bConfigurationValue of the currently active configuration.
|
|
// May use OS caches (no I/O) or block on a control transfer. Writes 0 to
|
|
// `config` if the device is unconfigured. Returns SUCCESS or NO_DEVICE.
|
|
get_configuration :: proc(dev_handle: Device_Handle, config: ^c.int) -> Error ---
|
|
// Set the active configuration for a device. A value of -1 puts the device in
|
|
// an unconfigured state. Calling with the already-active value acts as a
|
|
// lightweight reset. Cannot change configuration while interfaces are claimed.
|
|
// Blocking. Returns SUCCESS, or NOT_FOUND / BUSY / NOT_SUPPORTED / NO_DEVICE.
|
|
set_configuration :: proc(dev_handle: Device_Handle, configuration: c.int) -> Error ---
|
|
// Claim an interface on a device handle. Must be claimed before performing
|
|
// I/O on any of its endpoints. Purely logical (no bus I/O). Returns SUCCESS,
|
|
// or NOT_FOUND / BUSY / NO_DEVICE.
|
|
claim_interface :: proc(dev_handle: Device_Handle, interface_number: c.int) -> Error ---
|
|
// Release a previously claimed interface. Release all claimed interfaces
|
|
// before closing a handle. Blocking (sends a SET_INTERFACE request). Returns
|
|
// SUCCESS, or NOT_FOUND / NO_DEVICE.
|
|
release_interface :: proc(dev_handle: Device_Handle, interface_number: c.int) -> Error ---
|
|
// Activate an alternate setting for an interface (which must be claimed).
|
|
// Blocking. Returns SUCCESS, or NOT_FOUND / NO_DEVICE.
|
|
set_interface_alt_setting :: proc(dev_handle: Device_Handle, interface_number: c.int, alternate_setting: c.int) -> Error ---
|
|
// Clear the halt/stall condition for an endpoint. Cancel all pending
|
|
// transfers on the endpoint first. Blocking. Returns SUCCESS, or NOT_FOUND /
|
|
// NO_DEVICE.
|
|
clear_halt :: proc(dev_handle: Device_Handle, endpoint: u8) -> Error ---
|
|
// Perform a USB port reset to reinitialize a device. If the reset fails or
|
|
// the descriptors change, returns NOT_FOUND — close the handle and
|
|
// re-enumerate. Blocking, usually with a noticeable delay.
|
|
reset_device :: proc(dev_handle: Device_Handle) -> Error ---
|
|
// Determine if a kernel driver is active on an interface. If active, you
|
|
// cannot claim the interface. Not available on Windows. Returns 0 if no
|
|
// kernel driver is active, 1 if active, or a negative Error code.
|
|
kernel_driver_active :: proc(dev_handle: Device_Handle, interface_number: c.int) -> c.int ---
|
|
// Detach a kernel driver from an interface, allowing you to claim it. Not
|
|
// available on Windows. Returns SUCCESS, or NOT_FOUND / INVALID_PARAM /
|
|
// NO_DEVICE / NOT_SUPPORTED.
|
|
detach_kernel_driver :: proc(dev_handle: Device_Handle, interface_number: c.int) -> Error ---
|
|
// Re-attach an interface's kernel driver previously detached with
|
|
// `detach_kernel_driver()`. Not available on Windows. Returns SUCCESS, or
|
|
// NOT_FOUND / INVALID_PARAM / NO_DEVICE / NOT_SUPPORTED / BUSY.
|
|
attach_kernel_driver :: proc(dev_handle: Device_Handle, interface_number: c.int) -> Error ---
|
|
// Enable/disable libusb's automatic kernel driver detachment. When enabled,
|
|
// libusb detaches the kernel driver on `claim_interface()` and re-attaches it
|
|
// on `release_interface()`. Returns SUCCESS, or NOT_SUPPORTED on platforms
|
|
// without this capability.
|
|
set_auto_detach_kernel_driver :: proc(dev_handle: Device_Handle, enable: b32) -> Error ---
|
|
|
|
// ---- Miscellaneous ----
|
|
|
|
// Check at runtime if the loaded library has a given capability. Should be
|
|
// performed after `init_context()`, so the backend has updated its capability
|
|
// set. Returns nonzero if the capability is supported, 0 otherwise.
|
|
has_capability :: proc(capability: Capability) -> c.int ---
|
|
// Returns a constant string with the ASCII name of an Error or transfer
|
|
// status code (e.g. "LIBUSB_ERROR_IO"). Must not be freed.
|
|
error_name :: proc(errcode: Error) -> cstring ---
|
|
// Returns a pointer to a `Version` with the version of the running library.
|
|
get_version :: proc() -> ^Version ---
|
|
// Set the language used for translatable libusb messages (see `strerror()`).
|
|
// `locale` is a 2-letter ISO 639-1 code, optionally followed by region.
|
|
// Returns SUCCESS, or INVALID_PARAM / NOT_FOUND. Since version 1.0.21.
|
|
setlocale :: proc(locale: cstring) -> Error ---
|
|
// Returns a constant UTF-8 string describing an Error code, suitable for
|
|
// display to an end user. Must not be freed.
|
|
strerror :: proc(errcode: Error) -> cstring ---
|
|
|
|
// ---- USB descriptors ----
|
|
|
|
// Get the USB device descriptor for a device. Non-blocking; the descriptor is
|
|
// cached. Returns SUCCESS or an Error.
|
|
get_device_descriptor :: proc(dev: Device, desc: ^Device_Descriptor) -> Error ---
|
|
// Get the configuration descriptor for the currently active configuration.
|
|
// Free with `free_config_descriptor()`. Returns SUCCESS, or NOT_FOUND if the
|
|
// device is in an unconfigured state.
|
|
get_active_config_descriptor :: proc(dev: Device, config: ^^Config_Descriptor) -> Error ---
|
|
// Get a configuration descriptor by its index. Free with
|
|
// `free_config_descriptor()`. Returns SUCCESS, or NOT_FOUND.
|
|
get_config_descriptor :: proc(dev: Device, config_index: u8, config: ^^Config_Descriptor) -> Error ---
|
|
// Get a configuration descriptor with a specific bConfigurationValue. Free
|
|
// with `free_config_descriptor()`. Returns SUCCESS, or NOT_FOUND.
|
|
get_config_descriptor_by_value :: proc(dev: Device, bConfigurationValue: u8, config: ^^Config_Descriptor) -> Error ---
|
|
// Free a configuration descriptor obtained from `get_active_config_descriptor()`
|
|
// or `get_config_descriptor()`. Safe to call with nil.
|
|
free_config_descriptor :: proc(config: ^Config_Descriptor) ---
|
|
// Get the SuperSpeed endpoint companion descriptor for an endpoint. Free with
|
|
// `free_ss_endpoint_companion_descriptor()`. Returns SUCCESS, NOT_FOUND if not
|
|
// present, or another Error.
|
|
get_ss_endpoint_companion_descriptor :: proc(ctx: Context, endpoint: ^Endpoint_Descriptor, ep_comp: ^^Ss_Endpoint_Companion_Descriptor) -> Error ---
|
|
// Free an SS endpoint companion descriptor. Safe to call with nil.
|
|
free_ss_endpoint_companion_descriptor :: proc(ep_comp: ^Ss_Endpoint_Companion_Descriptor) ---
|
|
// Get a Binary Object Store (BOS) descriptor. Free with `free_bos_descriptor()`.
|
|
// Returns SUCCESS, NOT_FOUND if not present, or another Error.
|
|
get_bos_descriptor :: proc(dev_handle: Device_Handle, bos: ^^Bos_Descriptor) -> Error ---
|
|
// Free a BOS descriptor. Safe to call with nil.
|
|
free_bos_descriptor :: proc(bos: ^Bos_Descriptor) ---
|
|
// Get a USB 2.0 Extension descriptor from a BOS device capability. Free with
|
|
// `free_usb2_extension_descriptor()`. Returns SUCCESS or an Error.
|
|
get_usb2_extension_descriptor :: proc(ctx: Context, dev_cap: ^Bos_Dev_Capability_Descriptor, usb2_extension: ^^Usb2_Extension_Descriptor) -> Error ---
|
|
// Free a USB 2.0 Extension descriptor. Safe to call with nil.
|
|
free_usb2_extension_descriptor :: proc(usb2_extension: ^Usb2_Extension_Descriptor) ---
|
|
// Get a SuperSpeed USB Device Capability descriptor from a BOS device
|
|
// capability. Free with `free_ss_usb_device_capability_descriptor()`. Returns
|
|
// SUCCESS or an Error.
|
|
get_ss_usb_device_capability_descriptor :: proc(ctx: Context, dev_cap: ^Bos_Dev_Capability_Descriptor, ss_usb_device_cap: ^^Ss_Usb_Device_Capability_Descriptor) -> Error ---
|
|
// Free a SuperSpeed USB Device Capability descriptor. Safe to call with nil.
|
|
free_ss_usb_device_capability_descriptor :: proc(ss_usb_device_cap: ^Ss_Usb_Device_Capability_Descriptor) ---
|
|
// Get a SuperSpeedPlus USB Device Capability descriptor from a BOS device
|
|
// capability. Free with `free_ssplus_usb_device_capability_descriptor()`.
|
|
// Since version 1.0.27.
|
|
get_ssplus_usb_device_capability_descriptor :: proc(ctx: Context, dev_cap: ^Bos_Dev_Capability_Descriptor, ssplus_usb_device_cap: ^^Ssplus_Usb_Device_Capability_Descriptor) -> Error ---
|
|
// Free a SuperSpeedPlus USB Device Capability descriptor. Safe to call with
|
|
// nil. Since version 1.0.27.
|
|
free_ssplus_usb_device_capability_descriptor :: proc(ssplus_usb_device_cap: ^Ssplus_Usb_Device_Capability_Descriptor) ---
|
|
// Get a Container ID descriptor from a BOS device capability. Free with
|
|
// `free_container_id_descriptor()`. Returns SUCCESS or an Error.
|
|
get_container_id_descriptor :: proc(ctx: Context, dev_cap: ^Bos_Dev_Capability_Descriptor, container_id: ^^Container_Id_Descriptor) -> Error ---
|
|
// Free a Container ID descriptor. Safe to call with nil.
|
|
free_container_id_descriptor :: proc(container_id: ^Container_Id_Descriptor) ---
|
|
// Get a Platform descriptor from a BOS device capability. Free with
|
|
// `free_platform_descriptor()`. Since version 1.0.27.
|
|
get_platform_descriptor :: proc(ctx: Context, dev_cap: ^Bos_Dev_Capability_Descriptor, platform_descriptor: ^^Platform_Descriptor) -> Error ---
|
|
// Free a Platform descriptor. Safe to call with nil. Since version 1.0.27.
|
|
free_platform_descriptor :: proc(platform_descriptor: ^Platform_Descriptor) ---
|
|
// Retrieve a string descriptor in C-style ASCII. `data` is an output buffer
|
|
// of size `length`. Returns the number of bytes written, or a negative Error
|
|
// code.
|
|
get_string_descriptor_ascii :: proc(dev_handle: Device_Handle, desc_index: u8, data: [^]u8, length: c.int) -> c.int ---
|
|
// Get an array of interface association descriptors (IADs) for a given
|
|
// configuration index. Free with `free_interface_association_descriptors()`.
|
|
// Since version 1.0.27.
|
|
get_interface_association_descriptors :: proc(dev: Device, config_index: u8, iad_array: ^^Interface_Association_Descriptor_Array) -> Error ---
|
|
// Get an array of IADs for the currently active configuration. Free with
|
|
// `free_interface_association_descriptors()`. Since version 1.0.27.
|
|
get_active_interface_association_descriptors :: proc(dev: Device, iad_array: ^^Interface_Association_Descriptor_Array) -> Error ---
|
|
// Free an array of interface association descriptors. Safe to call with nil.
|
|
// Since version 1.0.27.
|
|
free_interface_association_descriptors :: proc(iad_array: ^Interface_Association_Descriptor_Array) ---
|
|
|
|
// ---- Device string (libusb 1.0.30+) ----
|
|
|
|
// Retrieve a device string descriptor (manufacturer, product, or serial
|
|
// number) as UTF-8. `data` is an output buffer of size `length`. Returns the
|
|
// number of bytes written (including the null terminator), or a negative
|
|
// Error code. Since version 1.0.30.
|
|
get_device_string :: proc(dev: Device, string_type: Device_String_Type, data: [^]u8, length: c.int) -> c.int ---
|
|
|
|
// ---- Raw I/O (libusb 1.0.30+) ----
|
|
|
|
// Check whether an endpoint supports WinUSB RAW_IO. Only endpoints using the
|
|
// WinUSB driver support it; all other backends return 0. The interface must
|
|
// be claimed. Returns 1 if supported, 0 if not, or a negative Error code.
|
|
// Since version 1.0.30.
|
|
endpoint_supports_raw_io :: proc(dev_handle: Device_Handle, endpoint: u8) -> c.int ---
|
|
// Enable/disable WinUSB RAW_IO for an endpoint on an open device. Can greatly
|
|
// improve throughput. While enabled, transfers must obey alignment rules: the
|
|
// buffer length must be a multiple of the endpoint's max packet size and
|
|
// `<= get_max_raw_io_transfer_size()`. Returns 0 (SUCCESS), or a negative
|
|
// Error code (NOT_SUPPORTED if the backend lacks RAW_IO). Since version 1.0.30.
|
|
endpoint_set_raw_io :: proc(dev_handle: Device_Handle, endpoint: u8, enable: b32) -> c.int ---
|
|
// Retrieve the maximum transfer size in bytes supported for WinUSB RAW_IO on
|
|
// an inbound bulk or interrupt endpoint. Returns a positive maximum transfer
|
|
// size, or a negative Error code (NOT_SUPPORTED if unsupported). Since version
|
|
// 1.0.30.
|
|
get_max_raw_io_transfer_size :: proc(dev_handle: Device_Handle, endpoint: u8) -> c.int ---
|
|
|
|
// ---- Device hotplug event notification ----
|
|
|
|
// Register a hotplug callback. It fires when a matching event occurs on a
|
|
// matching device, until deregistered or until the callback returns true.
|
|
// Pass `HOTPLUG_MATCH_ANY` for vendor_id / product_id / dev_class to match
|
|
// anything. If `flags` includes ENUMERATE, the callback also fires for all
|
|
// currently attached matching devices. `callback_handle` may be nil. Returns
|
|
// SUCCESS or an Error. Since version 1.0.16.
|
|
hotplug_register_callback :: proc(ctx: Context, events: Hotplug_Events, flags: Hotplug_Flags, vendor_id: c.int, product_id: c.int, dev_class: c.int, cb_fn: Hotplug_Callback_Fn, user_data: rawptr, callback_handle: ^Callback_Handle) -> Error ---
|
|
// Deregister a hotplug callback. Safe to call from within a hotplug callback.
|
|
// Since version 1.0.16.
|
|
hotplug_deregister_callback :: proc(ctx: Context, callback_handle: Callback_Handle) ---
|
|
// Get the user_data associated with a hotplug callback. Since version 1.0.24.
|
|
hotplug_get_user_data :: proc(ctx: Context, callback_handle: Callback_Handle) -> rawptr ---
|
|
|
|
// ---- Asynchronous device I/O ----
|
|
|
|
// Allocate up to `num_streams` USB bulk streams on the specified endpoints
|
|
// (which must all belong to the same interface). Stream id 0 is reserved; if
|
|
// N streams are allocated you may use ids 1..=N. Returns the number of streams
|
|
// allocated, or a negative Error code. Since version 1.0.19.
|
|
alloc_streams :: proc(dev_handle: Device_Handle, num_streams: u32, endpoints: [^]u8, num_endpoints: c.int) -> c.int ---
|
|
// Free bulk streams allocated with `alloc_streams()`. Streams are also freed
|
|
// automatically when releasing an interface. Returns SUCCESS or an Error.
|
|
// Since version 1.0.19.
|
|
free_streams :: proc(dev_handle: Device_Handle, endpoints: [^]u8, num_endpoints: c.int) -> Error ---
|
|
// Attempt to allocate a block of persistent DMA memory suitable for transfers
|
|
// against the device, allowing zero-copy. Returns nil on failure (many systems
|
|
// do not support this). Free with `dev_mem_free()`; do not use the FREE_BUFFER
|
|
// flag on such buffers. Since version 1.0.21.
|
|
dev_mem_alloc :: proc(dev_handle: Device_Handle, length: c.size_t) -> [^]u8 ---
|
|
// Free device memory allocated with `dev_mem_alloc()`. Returns SUCCESS or an
|
|
// Error.
|
|
dev_mem_free :: proc(dev_handle: Device_Handle, buffer: [^]u8, length: c.size_t) -> Error ---
|
|
// Allocate a transfer with the given number of isochronous packet descriptors
|
|
// (0 for control/bulk/interrupt). The returned transfer is pre-initialized.
|
|
// Free with `free_transfer()`. Returns nil on error.
|
|
alloc_transfer :: proc(iso_packets: c.int) -> ^Transfer ---
|
|
// Free a transfer allocated with `alloc_transfer()`. If the FREE_BUFFER flag
|
|
// is set and the buffer is non-nil, the buffer is also freed. Safe to call
|
|
// with nil. It is illegal to free an active (submitted, incomplete) transfer.
|
|
free_transfer :: proc(transfer: ^Transfer) ---
|
|
// Submit a transfer. Fires off the transfer and returns immediately. Returns
|
|
// SUCCESS, or NO_DEVICE / BUSY / NOT_SUPPORTED / INVALID_PARAM / another Error.
|
|
submit_transfer :: proc(transfer: ^Transfer) -> Error ---
|
|
// Asynchronously cancel a previously submitted transfer. Returns immediately;
|
|
// the callback is invoked later with status CANCELLED. Returns SUCCESS, or
|
|
// NOT_FOUND if the transfer is not in progress / already complete / already
|
|
// cancelled.
|
|
cancel_transfer :: proc(transfer: ^Transfer) -> Error ---
|
|
// Set a transfer's bulk stream id. Prefer `fill_bulk_stream_transfer()`.
|
|
// Since version 1.0.19.
|
|
transfer_set_stream_id :: proc(transfer: ^Transfer, stream_id: u32) ---
|
|
// Get a transfer's bulk stream id. Since version 1.0.19.
|
|
transfer_get_stream_id :: proc(transfer: ^Transfer) -> u32 ---
|
|
|
|
// ---- Polling and timing ----
|
|
|
|
// Attempt to acquire the event handling lock, which ensures only one thread
|
|
// monitors libusb's event sources at a time. Only needed if you poll()/select()
|
|
// on libusb's file descriptors directly. Returns 0 if the lock was obtained,
|
|
// 1 if it was not.
|
|
try_lock_events :: proc(ctx: Context) -> c.int ---
|
|
// Acquire the event handling lock, blocking until it is obtained. Only needed
|
|
// if you poll()/select() on libusb's file descriptors directly.
|
|
lock_events :: proc(ctx: Context) ---
|
|
// Release the lock acquired with `try_lock_events()` or `lock_events()`. Wakes
|
|
// up any threads blocked on `wait_for_event()`.
|
|
unlock_events :: proc(ctx: Context) ---
|
|
// Determine if it is still OK for this thread to be doing event handling. Call
|
|
// before polling; if it returns false, give up the events lock and retry the
|
|
// cycle. Returns true if event handling can start or continue, false if this
|
|
// thread must give up the events lock.
|
|
event_handling_ok :: proc(ctx: Context) -> b32 ---
|
|
// Determine if an active thread is handling events (i.e. holds the event
|
|
// handling lock). Returns true if a thread is handling events, false if none.
|
|
event_handler_active :: proc(ctx: Context) -> b32 ---
|
|
// Interrupt any active thread that is handling events. Mainly useful for
|
|
// interrupting a dedicated event-handling thread before calling `exit()`.
|
|
// Since version 1.0.21.
|
|
interrupt_event_handler :: proc(ctx: Context) ---
|
|
// Acquire the event waiters lock. Use when you want to be notified of event
|
|
// completion but another thread is handling events.
|
|
lock_event_waiters :: proc(ctx: Context) ---
|
|
// Release the event waiters lock.
|
|
unlock_event_waiters :: proc(ctx: Context) ---
|
|
// Wait for another thread to signal completion of an event. Must be called
|
|
// with the event waiters lock held. Blocks until the timeout expires, a
|
|
// transfer completes, or a thread releases the event handling lock. `tv` may
|
|
// be nil for an unlimited wait. Returns 0 after a transfer completes or
|
|
// another thread stops handling events, 1 if the timeout expired, or
|
|
// INVALID_PARAM.
|
|
wait_for_event :: proc(ctx: Context, tv: ^Timeval) -> c.int ---
|
|
// Handle any pending events in blocking mode (60s internal timeout). Kept
|
|
// mainly for backwards compatibility; prefer `handle_events_completed()`.
|
|
// Returns SUCCESS or an Error.
|
|
handle_events :: proc(ctx: Context) -> Error ---
|
|
// Handle any pending events, blocking up to `tv` (an all-zero timeval gives
|
|
// non-blocking behavior). Kept for backwards compatibility; prefer
|
|
// `handle_events_timeout_completed()`. Returns SUCCESS or an Error.
|
|
handle_events_timeout :: proc(ctx: Context, tv: ^Timeval) -> Error ---
|
|
// Like `handle_events_timeout()`, but if `completed` is non-nil this returns
|
|
// immediately (after obtaining the event lock) once the pointed-to flag is
|
|
// set, allowing race-free waiting for a specific transfer. The flag should be
|
|
// set from within the transfer callback. Returns SUCCESS, or INVALID_PARAM /
|
|
// another Error.
|
|
handle_events_timeout_completed :: proc(ctx: Context, tv: ^Timeval, completed: ^b32) -> Error ---
|
|
// Like `handle_events()`, with a `completed` flag for race-free waiting on a
|
|
// specific transfer (see `handle_events_timeout_completed()`). Returns SUCCESS
|
|
// or an Error.
|
|
handle_events_completed :: proc(ctx: Context, completed: ^b32) -> Error ---
|
|
// Handle pending events by polling file descriptors, without checking whether
|
|
// other threads are already doing so. Must be called with the event lock held.
|
|
// Returns SUCCESS, or INVALID_PARAM / another Error.
|
|
handle_events_locked :: proc(ctx: Context, tv: ^Timeval) -> Error ---
|
|
// Determine whether your application must apply special timing considerations
|
|
// when monitoring libusb's file descriptors. Returns 0 if you must call into
|
|
// libusb at times determined by `get_next_timeout()`, or 1 if all timeout
|
|
// events are handled internally or through regular file-descriptor activity.
|
|
pollfds_handle_timeouts :: proc(ctx: Context) -> c.int ---
|
|
// Determine the next internal timeout that libusb needs to handle. Only needed
|
|
// if you poll()/select() on libusb's file descriptors yourself; use the result
|
|
// as an upper bound for your poll timeout. Returns 0 if there are no pending
|
|
// timeouts, 1 if a timeout was returned, or a negative Error code.
|
|
get_next_timeout :: proc(ctx: Context, tv: ^Timeval) -> c.int ---
|
|
// Register notification functions for file-descriptor additions/removals as
|
|
// libusb's event sources change. Pass nil function pointers to remove the
|
|
// notifiers. Note that descriptors may already have been added before you
|
|
// register (e.g. at `init_context()` time).
|
|
set_pollfd_notifiers :: proc(ctx: Context, added_cb: Pollfd_Added_Cb, removed_cb: Pollfd_Removed_Cb, user_data: rawptr) ---
|
|
// Retrieve the list of file descriptors that should be polled as libusb event
|
|
// sources. Returns a NULL-terminated list of `Poll_Fd` pointers; free with
|
|
// `free_pollfds()`. Not available on Windows (returns nil).
|
|
get_pollfds :: proc(ctx: Context) -> [^]^Poll_Fd ---
|
|
// Free a pollfd list obtained from `get_pollfds()`. Safe to call with nil.
|
|
// Since version 1.0.20.
|
|
free_pollfds :: proc(pollfds: [^]^Poll_Fd) ---
|
|
|
|
// ---- Synchronous device I/O ----
|
|
|
|
// Perform a USB control transfer. `data` must point to a buffer of `wLength`
|
|
// bytes for the data stage (direction per bit 7 of `bmRequestType`). `timeout`
|
|
// is in milliseconds (0 = unlimited). Returns the number of bytes actually
|
|
// transferred, or a negative Error code.
|
|
control_transfer :: proc(dev_handle: Device_Handle, bmRequestType: u8, bRequest: u8, wValue: u16, wIndex: u16, data: [^]u8, wLength: u16, timeout: c.uint) -> c.int ---
|
|
// Perform a USB bulk transfer. `transferred`, if non-nil, receives the number
|
|
// of bytes actually transferred. `timeout` is in milliseconds (0 = unlimited).
|
|
// Returns SUCCESS, or TIMEOUT / PIPE / OVERFLOW / NO_DEVICE / another Error.
|
|
bulk_transfer :: proc(dev_handle: Device_Handle, endpoint: u8, data: [^]u8, length: c.int, transferred: ^c.int, timeout: c.uint) -> Error ---
|
|
// Perform a USB interrupt transfer. Behaves like `bulk_transfer()` but for
|
|
// interrupt endpoints. Returns SUCCESS or an Error.
|
|
interrupt_transfer :: proc(dev_handle: Device_Handle, endpoint: u8, data: [^]u8, length: c.int, transferred: ^c.int, timeout: c.uint) -> Error ---
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
// ----- Helper Procedures (from libusb static inline in libusb.h) ------------------------
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
// Convert a 16-bit value from host-endian to little-endian format.
|
|
cpu_to_le16 :: #force_inline proc "contextless" (x: u16) -> u16 {
|
|
return transmute(u16)u16le(x)
|
|
}
|
|
|
|
// Convert a 16-bit value from little-endian to host-endian format.
|
|
// Identical to `cpu_to_le16` since the conversion is its own inverse.
|
|
le16_to_cpu :: cpu_to_le16
|
|
|
|
// Get the data section of a control transfer. The data starts 8 bytes into
|
|
// the buffer, after the setup packet.
|
|
control_transfer_get_data :: #force_inline proc "contextless" (transfer: ^Transfer) -> [^]u8 {
|
|
return ([^]u8)(&transfer.buffer[CONTROL_SETUP_SIZE])
|
|
}
|
|
|
|
// Get the control setup packet from the start of a transfer's data buffer.
|
|
control_transfer_get_setup :: #force_inline proc "contextless" (transfer: ^Transfer) -> ^Control_Setup {
|
|
return (^Control_Setup)(transfer.buffer)
|
|
}
|
|
|
|
// Populate the setup packet (first 8 bytes of the data buffer) for a control
|
|
// transfer. The wValue, wIndex, and wLength values should be given in
|
|
// host-endian byte order; they will be converted to little-endian.
|
|
fill_control_setup :: proc "contextless" (
|
|
buffer: [^]u8,
|
|
bmRequestType: u8,
|
|
bRequest: u8,
|
|
wValue: u16,
|
|
wIndex: u16,
|
|
wLength: u16,
|
|
) {
|
|
setup := (^Control_Setup)(buffer)
|
|
setup.bmRequestType = bmRequestType
|
|
setup.bRequest = bRequest
|
|
setup.wValue = cpu_to_le16(wValue)
|
|
setup.wIndex = cpu_to_le16(wIndex)
|
|
setup.wLength = cpu_to_le16(wLength)
|
|
}
|
|
|
|
// Populate the required fields for a control transfer. If buffer is non-nil,
|
|
// the first 8 bytes are interpreted as a setup packet and the transfer length
|
|
// is inferred from the setup's wLength field.
|
|
fill_control_transfer :: proc "contextless" (
|
|
transfer: ^Transfer,
|
|
dev_handle: Device_Handle,
|
|
buffer: [^]u8,
|
|
callback: Transfer_Cb,
|
|
user_data: rawptr,
|
|
timeout: c.uint,
|
|
) {
|
|
transfer.dev_handle = dev_handle
|
|
transfer.endpoint = 0
|
|
transfer.type = .CONTROL
|
|
transfer.timeout = timeout
|
|
transfer.buffer = buffer
|
|
if buffer != nil {
|
|
setup := (^Control_Setup)(buffer)
|
|
transfer.length = c.int(CONTROL_SETUP_SIZE) + c.int(le16_to_cpu(setup.wLength))
|
|
}
|
|
transfer.user_data = user_data
|
|
transfer.callback = callback
|
|
}
|
|
|
|
// Populate the required fields for a bulk transfer.
|
|
fill_bulk_transfer :: proc "contextless" (
|
|
transfer: ^Transfer,
|
|
dev_handle: Device_Handle,
|
|
endpoint: u8,
|
|
buffer: [^]u8,
|
|
length: c.int,
|
|
callback: Transfer_Cb,
|
|
user_data: rawptr,
|
|
timeout: c.uint,
|
|
) {
|
|
transfer.dev_handle = dev_handle
|
|
transfer.endpoint = endpoint
|
|
transfer.type = .BULK
|
|
transfer.timeout = timeout
|
|
transfer.buffer = buffer
|
|
transfer.length = length
|
|
transfer.user_data = user_data
|
|
transfer.callback = callback
|
|
}
|
|
|
|
// Populate the required fields for a bulk stream transfer.
|
|
// Since version 1.0.19.
|
|
fill_bulk_stream_transfer :: proc "contextless" (
|
|
transfer: ^Transfer,
|
|
dev_handle: Device_Handle,
|
|
endpoint: u8,
|
|
stream_id: u32,
|
|
buffer: [^]u8,
|
|
length: c.int,
|
|
callback: Transfer_Cb,
|
|
user_data: rawptr,
|
|
timeout: c.uint,
|
|
) {
|
|
fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length, callback, user_data, timeout)
|
|
transfer.type = .BULK_STREAM
|
|
transfer_set_stream_id(transfer, stream_id)
|
|
}
|
|
|
|
// Populate the required fields for an interrupt transfer.
|
|
fill_interrupt_transfer :: proc "contextless" (
|
|
transfer: ^Transfer,
|
|
dev_handle: Device_Handle,
|
|
endpoint: u8,
|
|
buffer: [^]u8,
|
|
length: c.int,
|
|
callback: Transfer_Cb,
|
|
user_data: rawptr,
|
|
timeout: c.uint,
|
|
) {
|
|
transfer.dev_handle = dev_handle
|
|
transfer.endpoint = endpoint
|
|
transfer.type = .INTERRUPT
|
|
transfer.timeout = timeout
|
|
transfer.buffer = buffer
|
|
transfer.length = length
|
|
transfer.user_data = user_data
|
|
transfer.callback = callback
|
|
}
|
|
|
|
// Populate the required fields for an isochronous transfer.
|
|
fill_iso_transfer :: proc "contextless" (
|
|
transfer: ^Transfer,
|
|
dev_handle: Device_Handle,
|
|
endpoint: u8,
|
|
buffer: [^]u8,
|
|
length: c.int,
|
|
num_iso_packets: c.int,
|
|
callback: Transfer_Cb,
|
|
user_data: rawptr,
|
|
timeout: c.uint,
|
|
) {
|
|
transfer.dev_handle = dev_handle
|
|
transfer.endpoint = endpoint
|
|
transfer.type = .ISOCHRONOUS
|
|
transfer.timeout = timeout
|
|
transfer.buffer = buffer
|
|
transfer.length = length
|
|
transfer.num_iso_packets = num_iso_packets
|
|
transfer.user_data = user_data
|
|
transfer.callback = callback
|
|
}
|
|
|
|
// Set the length of all packets in an isochronous transfer to the same value.
|
|
set_iso_packet_lengths :: proc "contextless" (transfer: ^Transfer, length: c.uint) {
|
|
descs := ([^]Iso_Packet_Descriptor)(&transfer.iso_packet_desc)
|
|
for i in 0 ..< int(transfer.num_iso_packets) {
|
|
descs[i].length = length
|
|
}
|
|
}
|
|
|
|
// Locate the position of an isochronous packet within the buffer by
|
|
// accumulating lengths of all preceding packets.
|
|
get_iso_packet_buffer :: proc "contextless" (transfer: ^Transfer, packet: c.uint) -> [^]u8 {
|
|
if c.int(packet) >= transfer.num_iso_packets do return nil
|
|
descs := ([^]Iso_Packet_Descriptor)(&transfer.iso_packet_desc)
|
|
offset: uint = 0
|
|
for i in 0 ..< int(packet) {
|
|
offset += uint(descs[i].length)
|
|
}
|
|
return ([^]u8)(&transfer.buffer[offset])
|
|
}
|
|
|
|
// Locate the position of an isochronous packet within the buffer, assuming
|
|
// all packets are the same size as the first packet.
|
|
get_iso_packet_buffer_simple :: proc "contextless" (transfer: ^Transfer, packet: c.uint) -> [^]u8 {
|
|
if c.int(packet) >= transfer.num_iso_packets do return nil
|
|
descs := ([^]Iso_Packet_Descriptor)(&transfer.iso_packet_desc)
|
|
offset := uint(descs[0].length) * uint(packet)
|
|
return ([^]u8)(&transfer.buffer[offset])
|
|
}
|
|
|
|
// Retrieve a descriptor from the default control pipe. Convenience wrapper
|
|
// around `control_transfer()`.
|
|
get_descriptor :: proc(
|
|
dev_handle: Device_Handle,
|
|
desc_type: u8,
|
|
desc_index: u8,
|
|
data: [^]u8,
|
|
length: c.int,
|
|
) -> c.int {
|
|
return control_transfer(
|
|
dev_handle,
|
|
u8(Endpoint_Direction.IN),
|
|
u8(Standard_Request.GET_DESCRIPTOR),
|
|
u16(desc_type) << 8 | u16(desc_index),
|
|
0,
|
|
data,
|
|
u16(length),
|
|
1000,
|
|
)
|
|
}
|
|
|
|
// Retrieve a string descriptor from a device. The string returned is Unicode
|
|
// (UTF-16LE) as per the USB spec. Convenience wrapper around `control_transfer()`.
|
|
get_string_descriptor :: proc(
|
|
dev_handle: Device_Handle,
|
|
desc_index: u8,
|
|
langid: u16,
|
|
data: [^]u8,
|
|
length: c.int,
|
|
) -> c.int {
|
|
return control_transfer(
|
|
dev_handle,
|
|
u8(Endpoint_Direction.IN),
|
|
u8(Standard_Request.GET_DESCRIPTOR),
|
|
u16(u16(Descriptor_Type.STRING) << 8 | u16(desc_index)),
|
|
langid,
|
|
data,
|
|
u16(length),
|
|
1000,
|
|
)
|
|
}
|
|
|
|
// =============================================================================
|
|
// Tests
|
|
// =============================================================================
|
|
|
|
import "core:testing"
|
|
|
|
@(test)
|
|
init_test :: proc(t: ^testing.T) {
|
|
result := init(nil)
|
|
testing.expect_value(t, result, Error.SUCCESS)
|
|
if result == .SUCCESS {
|
|
exit(nil)
|
|
}
|
|
}
|