libusb API學(xué)習(xí)筆記-2
源碼API文檔
1. 函數(shù)學(xué)習(xí)
- 因?yàn)橐彩莿傞_(kāi)始學(xué)習(xí)佑颇,所以就根據(jù)函數(shù)的使用順序來(lái)看源碼低零。
1.1 libusb_init
- 初始化征绸,獲取libusb的上下文對(duì)象则剃。
- libusb是支持libusb_init(NULL)的拢切。但是有一點(diǎn)需要注意门扇,如果你在同一個(gè)進(jìn)程內(nèi)init了兩次雹有,你第二次獲得的上下文對(duì)象其實(shí)與第一次init的對(duì)象是同一個(gè)偿渡。且你在釋放上下文對(duì)象的時(shí)候,也需要釋放兩次霸奕。理由也很簡(jiǎn)單溜宽。同一個(gè)上下文對(duì)象其實(shí)是共用引用次數(shù)的,多次init也就是增加了引用次數(shù)质帅。是否的時(shí)候也是同樣的原理适揉。具體的內(nèi)容其實(shí)libusb源碼里注釋已經(jīng)都寫(xiě)的很清楚了。但如果你自己傳上下文對(duì)象進(jìn)來(lái)就沒(méi)有這個(gè)問(wèn)題了煤惩。
- 代碼注釋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) {//首先判斷一下是否傳進(jìn)來(lái)的是NULL嫉嘀,已經(jīng)默認(rèn)上下文對(duì)象是否已經(jīng)創(chuàng)建,如果是魄揉,就直接引用++剪侮,返回。這明顯是第二次init(NULL)的場(chǎng)景
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),則進(jìn)行初始化洛退,引用次數(shù)++瓣俯。
usbi_default_context = ctx;
default_context_refcnt++;
usbi_dbg("created default context");
}
...
...
...
}
- init內(nèi)部
- 首先第一步是將libusb_context中必要的對(duì)象進(jìn)行了初始化,包括但不限于以下三個(gè)
- usb_devs usb設(shè)備列表
- open_devs 已打開(kāi)的設(shè)備列表句柄
- hotplug_cbs 熱插拔的回調(diào)函數(shù)列表
list_init(&ctx->usb_devs); list_init(&ctx->open_devs); list_init(&ctx->hotplug_cbs);
- 如果是進(jìn)程內(nèi)第一個(gè)初始化的上下文對(duì)象兵怯,會(huì)再初始化一個(gè)活躍上下文對(duì)象列表彩匕,然后將初始化后的上下文對(duì)象存進(jìn)去。libusb_context的結(jié)構(gòu)體定義在libusbi.h中媒区。
if (first_init) {
first_init = 0;
list_init (&active_contexts_list);
}
list_add (&ctx->list, &active_contexts_list);
- 初始化libusb_context中io相關(guān)的參數(shù)驼仪,這一塊沒(méi)看懂
1.2 libusb_get_device_list
獲取設(shè)備列表,需要注意的是獲取列表的那個(gè)參數(shù)是個(gè)三級(jí)指針袜漩,也就是說(shuō)你需要傳個(gè)二級(jí)指針的地址進(jìn)去绪爸。
-
獲取的設(shè)備列表包括支持熱插拔和不支持熱插拔的設(shè)備。
//ctx 上下文對(duì)象 //list列表指針 //返回值是設(shè)備數(shù)目 ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx, libusb_device ***list);
1.3 libusb_get_device_address
- 獲取列表地址宙攻,不需要說(shuō)太多
1.4 libusb_get_device_descriptor
- 從代碼來(lái)看毡泻,很簡(jiǎn)單,就四行粘优,將libusb_device的device_descriptor拷貝給我們傳進(jìn)來(lái)的device_descriptor。
我代碼中使用過(guò)的是idVendor呻顽,idProduct雹顺,我用它們?nèi)ヅ袛嘣O(shè)備是否處于AOA模式,以及是否支持AOA模式廊遍。
AOA的PID有興趣的可以去Android官網(wǎng)看一下嬉愧。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
- 打開(kāi)設(shè)備,會(huì)返回一個(gè)handle喉前。為接下來(lái)的發(fā)送控制指令函數(shù)用的没酣。暫時(shí)不展開(kāi)看了王财。
1.5 libusb_control_transfer
- 給usb設(shè)備發(fā)送控制指令,并返回發(fā)送指令的結(jié)果裕便。我目前只用過(guò)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)
- 參數(shù)說(shuō)明
- dev_handle 這就是之前l(fā)ibopen函數(shù)獲得的句柄。源碼里的解釋:a handle for the device to communicate with偿衰。說(shuō)到底就是通信用的一個(gè)設(shè)備句柄挂疆。
- bmRequestType 請(qǐng)求字段的類型,比如我使用的是AOA相關(guān)的(LIBUSB_REQUEST_TYPE_VENDOR)下翎。源碼里我看了下缤言,有一些說(shuō)明,但也是不是很詳細(xì)视事。
首先libusb_control_transfer函數(shù)中調(diào)用了libusb_fill_control_setup函數(shù)胆萧,然后找到了一個(gè)結(jié)構(gòu)體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位代表
數(shù)據(jù)傳輸?shù)姆较颉1热缥疫x擇是要將AOA的command發(fā)送給usb設(shè)備乒裆,那么首先libusb_request_recipient的類型應(yīng)該是“LIBUSB_RECIPIENT_DEVICE = 0x00”套利,libusb_request_type應(yīng)該是標(biāo)準(zhǔn)類型(我只知道這個(gè),其他沒(méi)研究鹤耍。肉迫。。)“LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5)”稿黄,最后傳輸方向輸入喊衫,也就是device-to-host,“LIBUSB_ENDPOINT_IN = 0x80”杆怕,三種加起來(lái)就是“LIBUSB_RECIPIENT_DEVICE|LIBUSB_REQUEST_TYPE_STANDARD|LIBUSB_ENDPOINT_IN”族购,也就是0x40。
還有我去Android源碼里去看了看陵珍,找到了他們的定義寝杖,比較集中,應(yīng)該包含了所有的使用類型互纯。
//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 請(qǐng)求字段的內(nèi)容瑟幕,例如我請(qǐng)求字段的類型是LIBUSB_REQUEST_TYPE_STANDARD時(shí),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 這個(gè)簡(jiǎn)單理解為請(qǐng)求字段的id,可以隨意設(shè)置只盹。
- wIndex 簡(jiǎn)單點(diǎn)可以理解為字段內(nèi)容的位置辣往,假設(shè)你選擇準(zhǔn)備發(fā)送string類型的話,可以會(huì)有多個(gè)string殖卑,分開(kāi)發(fā)送站削,那肯定就會(huì)出現(xiàn)index從0開(kāi)始到N結(jié)束。
- data 字段內(nèi)容
- wLength 字段內(nèi)容長(zhǎng)度懦鼠,記得+1
- timeout 超時(shí)設(shè)置钻哩,以毫秒為單位。