libusb API学习笔记-2
源码API文档
1. 函数学习
- 因为也是刚开始学习,所以就根据函数的使用顺序来看源码。
1.1 libusb_init
- 初始化,获取libusb的上下文对象。
- libusb是支持libusb_init(NULL)的。但是有一点需要注意,如果你在同一个进程内init了两次,你第二次获得的上下文对象其实与第一次init的对象是同一个。且你在释放上下文对象的时候,也需要释放两次。理由也很简单。同一个上下文对象其实是共用引用次数的,多次init也就是增加了引用次数。是否的时候也是同样的原理。具体的内容其实libusb源码里注释已经都写的很清楚了。但如果你自己传上下文对象进来就没有这个问题了。
- 代码注释libusb-1.0.22/libusb/core.c
/* In order to keep things simple for more simplistic applications, it is
legal to pass NULL to all functions requiring a context pointer (as long as
you're sure no other code will attempt to use libusb from the same process).
When you pass NULL, the default context will be used. The default context
is created the first time a process calls libusb_init() when no other
context is alive. Contexts are destroyed during libusb_exit().
The default context is reference-counted and can be shared. That means that
if libusb_init(NULL) is called twice within the same process, the two
users end up sharing the same context. The deinitialization and freeing of
the default context will only happen when the last user calls libusb_exit().
In other words, the default context is created and initialized when its
reference count goes from 0 to 1, and is deinitialized and destroyed when
its reference count goes from 1 to 0. */
- 代码有两段可以看一下
int API_EXPORTED libusb_init(libusb_context **context)
{
...
...
...
if (!context && usbi_default_context) {//首先判断一下是否传进来的是NULL,已经默认上下文对象是否已经创建,如果是,就直接引用++,返回。这明显是第二次init(NULL)的场景
usbi_dbg("reusing default context");
default_context_refcnt++;
usbi_mutex_static_unlock(&default_context_lock);
return 0;
}
...
...
...
ctx = calloc(1, sizeof(*ctx) + priv_size);
if (!ctx) {
r = LIBUSB_ERROR_NO_MEM;
goto err_unlock;
}
/* default context should be initialized before calling usbi_dbg */
if (!usbi_default_context) {//如果是第一次init(NULL),则进行初始化,引用次数++。
usbi_default_context = ctx;
default_context_refcnt++;
usbi_dbg("created default context");
}
...
...
...
}
- init内部
- 首先第一步是将libusb_context中必要的对象进行了初始化,包括但不限于以下三个
- usb_devs usb设备列表
- open_devs 已打开的设备列表句柄
- hotplug_cbs 热插拔的回调函数列表
list_init(&ctx->usb_devs); list_init(&ctx->open_devs); list_init(&ctx->hotplug_cbs);
- 如果是进程内第一个初始化的上下文对象,会再初始化一个活跃上下文对象列表,然后将初始化后的上下文对象存进去。libusb_context的结构体定义在libusbi.h中。
if (first_init) {
first_init = 0;
list_init (&active_contexts_list);
}
list_add (&ctx->list, &active_contexts_list);
- 初始化libusb_context中io相关的参数,这一块没看懂
1.2 libusb_get_device_list
获取设备列表,需要注意的是获取列表的那个参数是个三级指针,也就是说你需要传个二级指针的地址进去。
-
获取的设备列表包括支持热插拔和不支持热插拔的设备。
//ctx 上下文对象 //list列表指针 //返回值是设备数目 ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx, libusb_device ***list);
1.3 libusb_get_device_address
- 获取列表地址,不需要说太多
1.4 libusb_get_device_descriptor
- 从代码来看,很简单,就四行,将libusb_device的device_descriptor拷贝给我们传进来的device_descriptor。
我代码中使用过的是idVendor,idProduct,我用它们去判断设备是否处于AOA模式,以及是否支持AOA模式。
AOA的PID有兴趣的可以去Android官网看一下。accessory mode Product ID
int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev,
struct libusb_device_descriptor *desc)
{
usbi_dbg("");
memcpy((unsigned char *) desc, (unsigned char *) &dev->device_descriptor,
sizeof (dev->device_descriptor));
return 0;
}
/** \ingroup libusb_desc
* A structure representing the standard USB device descriptor. This
* descriptor is documented in section 9.6.1 of the USB 3.0 specification.
* All multiple-byte fields are represented in host-endian format.
*/
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;
};
1.5 libusb_open
- 打开设备,会返回一个handle。为接下来的发送控制指令函数用的。暂时不展开看了。
1.5 libusb_control_transfer
- 给usb设备发送控制指令,并返回发送指令的结果。我目前只用过AOA模式切换的指令。
int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle,
uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
unsigned char *data, uint16_t wLength, unsigned int timeout)
- 参数说明
- dev_handle 这就是之前libopen函数获得的句柄。源码里的解释:a handle for the device to communicate with。说到底就是通信用的一个设备句柄。
- bmRequestType 请求字段的类型,比如我使用的是AOA相关的(LIBUSB_REQUEST_TYPE_VENDOR)。源码里我看了下,有一些说明,但也是不是很详细。
首先libusb_control_transfer函数中调用了libusb_fill_control_setup函数,然后找到了一个结构体libusb_control_setup,里面的代码中有一些注释可以了解下。
“Request type. Bits 0:4 determine recipient, see ref libusb_request_recipient. Bits 5:6 determine type, see ref libusb_request_type.Bit 7 determines data transfer direction, see ref libusb_endpoint_direction.”。可以看到0-4位代表接收者的类型,5-6位代表request的类型,7位代表
数据传输的方向。比如我选择是要将AOA的command发送给usb设备,那么首先libusb_request_recipient的类型应该是“LIBUSB_RECIPIENT_DEVICE = 0x00”,libusb_request_type应该是标准类型(我只知道这个,其他没研究。。。)“LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5)”,最后传输方向输入,也就是device-to-host,“LIBUSB_ENDPOINT_IN = 0x80”,三种加起来就是“LIBUSB_RECIPIENT_DEVICE|LIBUSB_REQUEST_TYPE_STANDARD|LIBUSB_ENDPOINT_IN”,也就是0x40。
还有我去Android源码里去看了看,找到了他们的定义,比较集中,应该包含了所有的使用类型。
//libusb源码
/** \ingroup libusb_desc
* Endpoint direction. Values for bit 7 of the
* \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme.
*/
enum libusb_endpoint_direction {
/** In: device-to-host */
LIBUSB_ENDPOINT_IN = 0x80,
/** Out: host-to-device */
LIBUSB_ENDPOINT_OUT = 0x00
};
enum libusb_request_type {
/** Standard */
LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5),
/** Class */
LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5),
/** Vendor */
LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5),
/** Reserved */
LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5)
};
/** \ingroup libusb_misc
* Recipient bits of the
* \ref libusb_control_setup::bmRequestType "bmRequestType" field in control
* transfers. Values 4 through 31 are reserved. */
enum libusb_request_recipient {
/** Device */
LIBUSB_RECIPIENT_DEVICE = 0x00,
/** Interface */
LIBUSB_RECIPIENT_INTERFACE = 0x01,
/** Endpoint */
LIBUSB_RECIPIENT_ENDPOINT = 0x02,
/** Other */
LIBUSB_RECIPIENT_OTHER = 0x03,
};
/** \ingroup libusb_asyncio
* Setup packet for control transfers. */
struct libusb_control_setup {
/** Request type. Bits 0:4 determine recipient, see
* \ref libusb_request_recipient. Bits 5:6 determine type, see
* \ref libusb_request_type. Bit 7 determines data transfer direction, see
* \ref libusb_endpoint_direction.
*/
uint8_t bmRequestType;
/** Request. If the type bits of bmRequestType are equal to
* \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD
* "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to
* \ref libusb_standard_request. For other cases, use of this field is
* application-specific. */
uint8_t bRequest;
/** Value. Varies according to request */
uint16_t wValue;
/** Index. Varies according to request, typically used to pass an index
* or offset */
uint16_t wIndex;
/** Number of bytes to transfer */
uint16_t wLength;
};
//Android源码
#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer
#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer
#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard
#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class
#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor
#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device
#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface
#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint
#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other
- bRequest 请求字段的内容,例如我请求字段的类型是LIBUSB_REQUEST_TYPE_STANDARD时,bRequest的值可能是如下:
/** \ingroup libusb_misc
* Standard requests, as defined in table 9-5 of the USB 3.0 specifications */
enum libusb_standard_request {
/** Request status of the specific recipient */
LIBUSB_REQUEST_GET_STATUS = 0x00,
/** Clear or disable a specific feature */
LIBUSB_REQUEST_CLEAR_FEATURE = 0x01,
/* 0x02 is reserved */
/** Set or enable a specific feature */
LIBUSB_REQUEST_SET_FEATURE = 0x03,
/* 0x04 is reserved */
/** Set device address for all future accesses */
LIBUSB_REQUEST_SET_ADDRESS = 0x05,
/** Get the specified descriptor */
LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06,
/** Used to update existing descriptors or add new descriptors */
LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07,
/** Get the current device configuration value */
LIBUSB_REQUEST_GET_CONFIGURATION = 0x08,
/** Set device configuration */
LIBUSB_REQUEST_SET_CONFIGURATION = 0x09,
/** Return the selected alternate setting for the specified interface */
LIBUSB_REQUEST_GET_INTERFACE = 0x0A,
/** Select an alternate interface for the specified interface */
LIBUSB_REQUEST_SET_INTERFACE = 0x0B,
/** Set then report an endpoint's synchronization frame */
LIBUSB_REQUEST_SYNCH_FRAME = 0x0C,
/** Sets both the U1 and U2 Exit Latency */
LIBUSB_REQUEST_SET_SEL = 0x30,
/** Delay from the time a host transmits a packet to the time it is
* received by the device. */
LIBUSB_SET_ISOCH_DELAY = 0x31,
};
- wValue 这个简单理解为请求字段的id,可以随意设置。
- wIndex 简单点可以理解为字段内容的位置,假设你选择准备发送string类型的话,可以会有多个string,分开发送,那肯定就会出现index从0开始到N结束。
- data 字段内容
- wLength 字段内容长度,记得+1
- timeout 超时设置,以毫秒为单位。