学习libusb
1、libusb学习网站
website:http://libusb.info/ API:http://libusb.sourceforge.net/api-1.0/libusb_api.html download:https://github.com/libusb/libusb mailing list:http://mailing-list.libusb.info libusb test demo:https://github.com/crazybaoli/libusb-testhttps://github.com/libusb/libusb/blob/master/examples/xusb.c
2、安装
提示:configure: error: “udev support requested but libudev not installed” 解决:sudo apt-get install libudev-dev
一般来说可能没有问题,直接configure 、 make 、make install三部曲即可。
当前文件夹进行局部安装,即拿来就用,不需要全局安装: 无非就是需要libusb.h头文件,以及编译生成的so文件。 linux的so文件只能自己编译出来,没有现成可下载的。 D:\Github\Storage\c++\udev\libusb\局部使用
3、libusbi.h和libusb.h
libusbi.h: Internal header for libusb libusb.h: Public libusb header file 但是还有一个libusb和libusbx,很是让人捉摸不透。 libusb是一个跨平台的usb驱动框架。libusb原始项目在2010年后基本没有更新,曾有libusbx项目2012年从libusb分出来,2014年1月26日又合并回libusb了。当时的libusbx-1.0.18和libusb-1.0.18其实完全一样,相当于libusbx替换了libusb的代码!后续的版本其实都是基于libusbx的代码了! 参考:https://blog.csdn.net/qq_43248127/article/details/113746403
发现http://libusbx.org网站已空空如也,正版网页是http://libusb.info。
struct libusb_device {
/* lock protects refcnt, everything else is finalized at initialization
* time */
usbi_mutex_t lock;
int refcnt;
struct libusb_context *ctx;
uint8_t bus_number;
uint8_t port_number;
struct libusb_device* parent_dev;
uint8_t device_address;
uint8_t num_configurations;
enum libusb_speed speed;
struct list_head list;
unsigned long session_data;
struct libusb_device_descriptor device_descriptor;
int attached;
unsigned char os_priv
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
[] /* valid C99 code */
#else
[0] /* non-standard, but usually working code */
#endif
;
};
struct libusb_device_descriptor {
/** Size of this descriptor (in bytes) */
uint8_t bLength;
/** Descriptor type. Will have value
* \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this
* context. */
uint8_t bDescriptorType;
/** USB specification release number in binary-coded decimal. A value of
* 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */
uint16_t bcdUSB;
/** USB-IF class code for the device. See \ref libusb_class_code. */
uint8_t bDeviceClass;
/** USB-IF subclass code for the device, qualified by the bDeviceClass
* value */
uint8_t bDeviceSubClass;
/** USB-IF protocol code for the device, qualified by the bDeviceClass and
* bDeviceSubClass values */
uint8_t bDeviceProtocol;
/** Maximum packet size for endpoint 0 */
uint8_t bMaxPacketSize0;
/** USB-IF vendor ID */
uint16_t idVendor;
/** USB-IF product ID */
uint16_t idProduct;
/** Device release number in binary-coded decimal */
uint16_t bcdDevice;
/** Index of string descriptor describing manufacturer */
uint8_t iManufacturer;
/** Index of string descriptor describing product */
uint8_t iProduct;
/** Index of string descriptor containing device serial number */
uint8_t iSerialNumber;
/** Number of possible configurations */
uint8_t bNumConfigurations;
};4、解析config descriptor
static void parse_descriptor(const void *source, const char *descriptor, void *dest)此函数无非是在处理大小端的问题,将部分多字节数据进行调整端位。
其中const char *descriptor参数则是判断解析多少位,如bbw,即解析到wTotalLength成员变量,如果想解析到bConfigurationValue成员变量,则需要使用bbwbb。
/** \ingroup libusb_desc
* A structure representing the standard USB configuration descriptor. This
* descriptor is documented in section 9.6.3 of the USB 3.0 specification.
* All multiple-byte fields are represented in host-endian format.
*/
struct libusb_config_descriptor {
/** Size of this descriptor (in bytes) */
uint8_t bLength;
/** Descriptor type. Will have value
* \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG
* in this context. */
uint8_t bDescriptorType;
/** Total length of data returned for this configuration */
uint16_t wTotalLength;
/** Number of interfaces supported by this configuration */
uint8_t bNumInterfaces;
/** Identifier value for this configuration */
uint8_t bConfigurationValue;
/** Index of string descriptor describing this configuration */
uint8_t iConfiguration;
/** Configuration characteristics */
uint8_t bmAttributes;
/** Maximum power consumption of the USB device from this bus in this
* configuration when the device is fully operation. Expressed in units
* of 2 mA when the device is operating in high-speed mode and in units
* of 8 mA when the device is operating in super-speed mode. */
uint8_t MaxPower;
/** Array of interfaces supported by this configuration. The length of
* this array is determined by the bNumInterfaces field. */
const struct libusb_interface *interface;
/** Extra descriptors. If libusb encounters unknown configuration
* descriptors, it will store them here, should you wish to parse them. */
const unsigned char *extra;
/** Length of the extra descriptors, in bytes. Must be non-negative. */
int extra_length;
};另外说明,如果是多个configuration时,即bNumConfigurations不为1。而其中bConfigurationValue并不一定是按照1开始往上递增,因此需要匹配时最好是通过这个值进行匹配,官方也是通过这种死办法,一个一个的遍历获取描述符,然后比较bConfigurationValue值,如在libusb库descriptor.c文件中:
int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev,
uint8_t bConfigurationValue, struct libusb_config_descriptor **config)5、简介
开发文档:https://libusb.sourceforge.io/api-1.0/
libusb是一个跨平台的用户空间USB库,它允许应用程序访问USB设备。它提供了一组API,使开发人员能够在不需要内核驱动程序的情况下与USB设备进行通信。
6、源码整体理解
https://mp.weixin.qq.com/s/KrxiqmJu35ZcrAsnvaFgPQ
io.c: 实现了libusb库中的异步I/O操作,包括异步读写、取消异步操作等功能。
hotplug.c: 实现了libusb库中的热插拔功能,包括注册和注销热插拔事件、处理热插拔事件等功能。
core.c: 实现了libusb库的核心功能,包括设备枚举、设备打开和关闭、控制传输、批量传输、中断传输等功能。
strerror.c:实现了libusb库中的错误处理功能,包括将错误码转换为错误信息字符串等功能。
sync.c: 实现了libusb库中的同步传输功能,包括同步控制传输、同步批量传输、同步中断传输等功能。
descriptor.c:实现了libusb库中的设备描述符解析功能,包括解析设备描述符、配置描述符、接口描述符、端点描述符等信息。这些信息对于访问和控制USB设备非常重要,因为它们描述了USB设备的各种属性和特性。
os文件夹:包含了针对不同操作系统的底层实现代码。由于不同操作系统的USB驱动实现方式不同,因此需要针对不同的操作系统编写不同的底层实现代码。在os文件夹中,可以找到针对Windows、Linux、macOS等操作系统的实现代码。这些代码实现了USB设备的枚举、打开、读写等基本操作,为上层的应用程序提供了方便的接口。在使用libusb库时,需要根据所使用的操作系统选择相应的实现代码进行编译和链接。
libusbi.h: 定义了libusb库的内部数据结构和函数接口,包括libusb_context、libusb_device、libusb_device_handle等结构体和函数。这些数据结构和函数接口是libusb库的核心部分,它们提供了访问和控制USB设备的基本框架。
libusb.h: 定义了libusb库的外部API函数接口,包括libusb_init、libusb_open、libusb_control_transfer等函数。这些函数接口是开发者使用libusb库的主要入口,通过这些函数可以访问和控制USB设备。
7、常用接口介绍
alternate settings <==> altsetting superspeed <==> ss BOS是USB设备的一个标准描述符,全称为"Binary Object Store"。BOS Device Capability descriptor是BOS描述符中的一个子描述符,用于描述USB设备的特定功能和能力。BOS Device Capability descriptor包含了一个Capability Type字段和一些特定于该类型的数据字段。Capability Type字段指定了该描述符所描述的功能类型,例如Wireless USB、USB 3.0等。BOS Device Capability descriptor可以帮助USB主机了解USB设备的特定功能和能力,从而更好地管理和控制USB设备。
/** \ingroup dev
* USB capability types
*/
enum libusb_bos_type {
/** Wireless USB device capability */
LIBUSB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1,
/** USB 2.0 extensions */
LIBUSB_BT_USB_2_0_EXTENSION = 2,
/** SuperSpeed USB device capability */
LIBUSB_BT_SS_USB_DEVICE_CAPABILITY = 3,
/** Container ID type */
LIBUSB_BT_CONTAINER_ID = 4,
};libusb.h: libusb_class_code:设备接口类别 libusb_descriptor_type:描述符类型 libusb_endpoint_direction:端点方向 libusb_transfer_type:传输类型(内含第五种传输类型BULK STREAM) libusb_standard_request:标准请求 libusb_xxxxx_descriptor:描述符结构体 libusb_speed:速度 libusb_error:错误码 libusb_transfer_status:传输状态
7-1.初始化与反初始化
libusb_init:初始化 libusb_exit:反初始化
7-2.枚举设备
libusb_get_device_list:获取设备列表 libusb_free_device_list:释放设备列表 libusb_get_device:获取设备信息 libusb_get_configuration:获取配置信息 libusb_set_configuration:设备配置
7-3.设备控制
libusb_open:打开设备 libusb_close:关闭设备 libusb_open_device_with_vid_pid:打开设备 libusb_reset_device:复位设备
7-4.接口激活与绑定
libusb_kernel_driver_active:接口驱动激活 libusb_detach_kernel_driver:从接口中分离内核驱动程序 libusb_attach_kernel_driver:重新附加接口的内核驱动程序 libusb_set_auto_detach_kernel_driver:启用/禁用 libusb 的自动内核驱动程序分离
7-5.接口声明和配置
libusb_claim_interface:声明一个接口 libusb_release_interface:释放声明的接口 libusb_set_interface_alt_setting :激活接口的备用设置。该接口必须先前已使用libusb_claim_interface()声明
7-6.端点
libusb_clear_halt: 清除端点的停止/停止条件
7-7.描述符
libusb_get_device_descriptor:获取设备描述符===>只是做一个拷贝操作 libusb_get_active_config_descriptor:获取当前活动配置的配置描述符 libusb_get_config_descriptor:根据索引获取 USB 配置描述符 libusb_get_config_descriptor_by_value:获取具有特定 bConfigurationValue 的 USB 配置描述符 libusb_free_config_descriptor:释放配置描述符
7-8.其他描述符
libusb_get_bos_descriptor:获取bos描述符 libusb_free_bos_descriptor :释放bos描述符 libusb_get_usb_2_0_extension_descriptor:获取usb 2.0 扩展 libusb_free_usb_2_0_extension_descriptor :释放usb 2.0 扩展 libusb_get_string_descriptor_ascii :字符串描述符
7-9.热插拔事件
libusb_hotplug_register_callback:注册一个热插拔回调函数 libusb_hotplug_deregister_callback :注销一个热插拔回调函数 libusb_hotplug_get_user_data:获取与热插拔回调关联的 user_data
7-10.同步IO之控制传输
libusb_control_transfer:控制传输
8、常规使用流程
- 初始化libusb usb库(libusb_init、libusb_set_debug)
- 打开指定设备(libusb_open/libusb_open_device_with_vid_pid)
- 获取某个接口的in和out端点地址(libusb_get_config_descriptor、libusb_endpoint_descriptor)
- 设备驱动分离(libusb_set_auto_detach_kernel_driver/libusb_detach_kernel_driver)
- 获取接口权限(libusb_claim_interface)
- 读写设备(如根据端口地址libusb_bulk_transfer)
- 关闭设备(libusb_close)
- 关闭库(libusb_exit)
9、libusb_device_handle和libusb_device区别和转换
libusb_device和libusb_device_handle都是libusb库中的结构体,但它们的作用不同。
libusb_device结构体代表一个USB设备,它包含了设备的描述信息,如设备的厂商ID、产品ID、设备地址等。通过调用libusb_get_device_list()函数可以获取系统中所有已连接的USB设备的libusb_device结构体列表。
libusb_device_handle结构体代表一个已打开的USB设备句柄,它可以用于与设备进行通信。通过调用libusb_open()函数可以打开一个USB设备,并返回一个libusb_device_handle结构体。使用libusb_device_handle结构体可以进行USB设备的读写操作,如发送控制命令、读取设备描述符、读写端点等。
因此,libusb_device结构体用于描述USB设备的信息,而libusb_device_handle结构体用于与USB设备进行通信。
libusb_device转换成libusb_device_handle: libusb_open(libusb_device, libusb_device_handle)
libusb_device_handle转换成libusb_device: libusb_device = libusb_get_device(libusb_device_handle)
10、libusb_context上下文的作用
libusb_context是libusb库的上下文环境,它是libusb库的核心数据结构,用于管理USB设备的连接和通信。在使用libusb库时,需要先创建一个libusb_context对象,然后通过该对象进行USB设备的操作。
libusb_context对象包含了libusb库的全局状态信息,例如USB设备的列表、设备的状态等。在创建libusb_context对象时,libusb库会初始化USB子系统,并且在程序退出时自动释放资源。
虽然在某些情况下可以将libusb_context参数设置为NULL,但这并不是推荐的做法。如果不传入libusb_context参数,libusb库会自动创建一个默认的libusb_context对象,但这可能会导致一些问题,例如在多线程环境下可能会出现竞争条件。因此,建议在使用libusb库时,显式地创建和销毁libusb_context对象。
libusb_context在调用libusb_init函数后会进行赋值,正如上面所说置为NULL也是能获取信息,但是不推荐。 代码见:D:\Github\Storage\c++\udev\libusb\libusb入门\libusb_context.c
11、在windows系统上面使用libusb
下载Source code(zip)里面有现成的代码项目,可以参考里面的使用。 https://www.usbzh.com/article/detail-482.htmlhttps://blog.csdn.net/zb774095236/article/details/83748747
其实很简单,导入libusb.h和libusb-1.0.lib文件就可以了,然后就跟在linux系统下面使用是一样的效果。 代码见:D:\Github\Storage\c++\udev\libusb\windows\LibusbExample
12、在windows系统上面无法使用libusb获取字符串描述符
无法获取字符串描述符,需要进行通信获取,一定需要替换成特定的驱动才能完成,这样才能使用libusb_open或者libusb_open_device_with_vid_pid才能成功,否则使用不了。
https://blog.csdn.net/qq_36098477/article/details/127525152 假如我现在插入一个U盘就开始调用LibUSB库进行Open操作,这样是一定会返回错误的,因为LibUSB本身不是驱动,实际上也是要调用驱动留出的系统调用接口进行数据和指令传递的(这里类比linux的特性,表述可能些许不合适)。当这个设备底层根本不是LibUSB需要的接口的时候,当然是无法正常调用。
此时需要将该设备的驱动换成合适的低级驱动(linux的优势就出来了),LibUSB库在Windows平台上是基于WinUSB底层驱动去开发的。因此最适合LibUSB开发的底层驱动当然是WinUSB。博主尝试过使用linusb-win32等其他的驱动,他们可以open设备但是在claim接口的时候会有掉设备的情况(一claim就听到Windows掉USB设备的声音,正常后不会这样),直接导致transfer的时候返回LIBUSB_ERROR_IO(-1)。因此,在进行Windows下的LibUSB开发之前先解决你的驱动问题。
驱动问题的解决方式是通过zadig工具进行驱动替换,首先插入你的设备,list一下获得设备名单,选择你的设备,选择winUSB驱动,replace即可。不需要有网也能安装。
因此不建议使用libusb库。 但是测试成功demo有: U盘直接使用zadig替换成功了(无需重启),但是替换摄像头的时候花费很长时间,但是替换成功了,并且需要重启虚拟机后才能正常使用。 备注:使用zadig替换驱动后设备无法正常使用。
所以只能参考usbview代码去修改:https://github.com/microsoft/Windows-driver-samples/tree/main/usb/usbview 参考uscview.c文件的RefreshTree函数 需要参考微软的usbview源代码进行参考编写: 在uvcview.c文件中:
函数追踪:从函数开始RefreshTree--EnumerateHostControllers--EnumerateHostController--EnumerateHub--EnumerateHubPorts
设备描述符就是:connectionInfoEx->DeviceDescriptor 其他描述符信息也都在EnumerateHubPorts函数里面。
12-1、SetWindowText函数报错
修改字符集:项目-属性-配置属性-常规-字符集-未设置
12-2、GUID_DEVINTERFACE_USB_DEVICE未定义
怎么修改都不行:
- 引入头文件#include <usbiodef.h>和#include <initguid.h>
- 导入#pragma comment(lib, "setupapi.lib")和#pragma comment(lib, "winusb.lib") 都会报无法解析的外部符号错误,最终还是直接把文件中的定义拷贝过来定义就行了。
#include <initguid.h>
/* A5DCBF10-6530-11D2-901F-00C04FB951ED */
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, \
0xC0, 0x4F, 0xB9, 0x51, 0xED);这个值可见文件,也可以通过usbtreeview软件查看设备的Device Path能看见这个值。
12-3、方案一:从usbview中摘抄关键函数使用
发现无法直接通过USB设备句柄进行DeviceIoControl函数通信,尝试了许久已放弃。 https://www.coder.work/article/7955478https://bbs.csdn.net/topics/617112992http://www.hzhcontrols.com/new-238393.htmlhttp://www.manongjc.com/detail/7-xhbooqfnezctzhb.htmlhttps://www.debugease.com/vc/2669312.html
hid设备:https://blog.csdn.net/qq_39554698/article/details/99586564
这篇文章让我最好奇,很想知道他实现了吗?无赖需要付费:https://blog.csdn.net/trustbo/article/details/50053229
12-4、方案二:备选直接使用usbvew代码
最终还是选择了妥协,先枚举hub,然后通过hub的各个port再去枚举usb设备。
奇怪之一:EnumerateAllDevicesWithGuid函数中,遍历SetupDiEnumDeviceInfo到最后一个时,调用FreeDeviceInfoNode函数偶尔会出现崩溃问题,然后注释掉就正常了。通过奇怪之二后发现也是没有对malloc的内存进行初始化,是同一个问题。
奇怪之二:GetStringDescriptors函数中,在遍历StringDescNodeHead时,Next指针存在异常,大概率会出现乱踩内存崩溃问题,但是usbview源代码没有这个问题。查了半天才发现是malloc函数分配内存后没有进行0初始化,这事情说明了malloc后初始化的重要性。为何源代码没有这个问题呢?原因是它使用了GlobalAlloc函数进行分配,我修改了这个函数到malloc。
在Windows操作系统中,GlobalAlloc函数用于在进程的堆中分配指定大小的内存块,并返回一个指向该内存块的全局唯一句柄。该函数的声明如下:
c HGLOBAL GlobalAlloc( UINT uFlags, SIZE_T dwBytes ); 其中,参数uFlags指定内存分配的方式,可以是以下值之一:
GMEM_FIXED:分配固定内存,返回的句柄指向的内存块不会移动。 GMEM_MOVEABLE:分配可移动内存,返回的句柄指向的内存块可以移动。 GMEM_ZEROINIT:分配内存时将其初始化为0。 参数dwBytes指定要分配的内存块的大小,以字节为单位。
使用GlobalAlloc函数分配的内存块可以通过GlobalLock函数获取指向该内存块的指针,通过GlobalUnlock函数释放该指针。使用GlobalFree函数释放内存块。
需要注意的是,GlobalAlloc函数分配的内存块是在进程的堆中分配的,因此在使用完毕后需要及时释放,否则可能会导致内存泄漏。
12-5、CSDN付费文章破解
https://www.jianshu.com/p/8683c79adcb5 然而百度已下线百度快照功能。 https://zhuanlan.zhihu.com/p/513246692?utm_id=0 百度文库:https://blog.csdn.net/m0_64139004/article/details/127918651https://www.zhihu.com/question/320230733
13、引入cJSON库
由于之前做了配置修改,导致引入后报大量的错误,如:
“初始化”: 无法从“void *(__cdecl *)(std::size_t)”转换为“void *(__stdcall *)(std::size_t)” UsbviewGetDescriptor D:\Users\User\My Document\Visual Studio 2015\Projects\UsbviewGetDescriptor\UsbviewGetDescriptor\cJSON.c 83原因是属性-》C/C++-》高级-》调用约定-》__stdcall(/Gz),这样配置后还有“main”: 必须是“__cdecl”。 恢复默认值就解决了:https://blog.csdn.net/flyingworm_eley/article/details/6516540 __cdecl(/Gd)
消除警告:'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. 属性-》C/C++-》预处理器-》预处理器定义-》_CRT_SECURE_NO_WARNINGS
错误 LNK2005 _EnumeratedHCListHead 已经在 devnode.obj 中定义 纯c项目不支持这种语法:
#pragma once
#ifndef __ADD_H__
#define __ADD_H__
int a;
int b = 2;
int add(int x, int y);
#endif // __ADD_H__// main.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "add.h"
int _tmain(int argc, _TCHAR* argv[])
{
printf("%d\n", add(3, 4));
return 0;
}#include "stdafx.h"
#include "add.h"
int add(int x, int y)
{
return x + y;
}在vs项目中编译只有b是多次定义,a不是。但是在linux中就神奇了:
[root@ubuntu0006:~/cmake] #gcc main.c add.c
/tmp/ccRvNcFB.o:(.data+0x0): `b'被多次定义
/tmp/ccrLSfLK.o:(.data+0x0):第一次在此定义
collect2: error: ld returned 1 exit status
[root@ubuntu0006:~/cmake] #g++ main.c add.c
/tmp/cccJVJ53.o:(.bss+0x0): `a'被多次定义
/tmp/ccAZh1jz.o:(.bss+0x0):第一次在此定义
/tmp/cccJVJ53.o:(.data+0x0): `b'被多次定义
/tmp/ccAZh1jz.o:(.data+0x0):第一次在此定义
collect2: error: ld returned 1 exit status由于头文件在编译时会被包含到每个包含它的源文件中,因此在编译时会导致a和b被多次定义。正确的修改方式是:
#pragma once
#ifndef __ADD_H__
#define __ADD_H__
extern int a;
extern int b;
int add(int x, int y);
#endif // __ADD_H__#include "add.h"
int a;
int b = 2;
int add(int x, int y)
{
return x + y;
}使用extern关键字声明全局变量a和b,然后在add.cpp中进行定义和初始化,可以避免重复定义的问题。
14、一开始项目还有控制台弹框,但是修改配置后会一闪而过
修改项目配置,右键点击项目,在右键菜单中选择属性,然后在弹出的对话框左侧列表中中选择“配置属性”-->“链接器”-->“系统”,然后在右侧的列表中,在第一项”子系统“的值中选择”控制台(/SUBSUSTEM:CONSOLE)”
另外一种方法:system("pause");
15、错误码查看
/** \ingroup libusb_misc
* Error codes. Most libusb functions return 0 on success or one of these
* codes on failure.
* You can call libusb_error_name() to retrieve a string representation of an
* error code or libusb_strerror() to get an end-user suitable description of
* an error code.
*/
enum libusb_error {
/** Success (no error) */
LIBUSB_SUCCESS = 0,
/** Input/output error */
LIBUSB_ERROR_IO = -1,
/** Invalid parameter */
LIBUSB_ERROR_INVALID_PARAM = -2,
/** Access denied (insufficient permissions) */
LIBUSB_ERROR_ACCESS = -3,
/** No such device (it may have been disconnected) */
LIBUSB_ERROR_NO_DEVICE = -4,
/** Entity not found */
LIBUSB_ERROR_NOT_FOUND = -5,
/** Resource busy */
LIBUSB_ERROR_BUSY = -6,
/** Operation timed out */
LIBUSB_ERROR_TIMEOUT = -7,
/** Overflow */
LIBUSB_ERROR_OVERFLOW = -8,
/** Pipe error */
LIBUSB_ERROR_PIPE = -9,
/** System call interrupted (perhaps due to signal) */
LIBUSB_ERROR_INTERRUPTED = -10,
/** Insufficient memory */
LIBUSB_ERROR_NO_MEM = -11,
/** Operation not supported or unimplemented on this platform */
LIBUSB_ERROR_NOT_SUPPORTED = -12,
/* NB: Remember to update LIBUSB_ERROR_COUNT below as well as the
message strings in strerror.c when adding new error codes here. */
/** Other error */
LIBUSB_ERROR_OTHER = -99
};
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */