libusb API学习笔记-2

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 超时设置,以毫秒为单位。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容