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 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 . 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) } }