libusb学习笔记(4)

API说明:

先检查是否支持热插拔。
用 LIBUSB_CAP_HAS_HOTPLUG 参数来调用 libusb_has_capability() 以确认是否支持热插拔。

libusb_context *libusbCtx = NULL;
libusb_init(&libusbCtx);
if(libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)){
    printf("支持热插拔\n");
}
libusb_exit(libusbCtx);

int libusb_hotplug_register_callback(libusb_context *ctx, ...);
注册一个热插拔回调函数。

int libusb_hotplug_register_callback(
    libusb_context *ctx,        // libusb环境上下文
    int             events,     // 触发此回调的热插拔事件
    int             flags,      // 热插拔标志
    int             vendor_id,  // 要匹配的VID,  或设置为 LIBUSB_HOTPLUG_MATCH_ANY 来匹配所有。
    int             product_id, // 要匹配的PID,  或设置为 LIBUSB_HOTPLUG_MATCH_ANY 来匹配所有。
    int             dev_class,  // 要匹配的class,或设置为 LIBUSB_HOTPLUG_MATCH_ANY 来匹配所有。
    libusb_hotplug_callback_fn      cb_fn,          // 回调函数
    void                           *user_data,      // 传输给回调函数的用户数据。
    libusb_hotplug_callback_handle *callback_handle // 用于返回回调句柄。
);

// 触发回调的事件
enum libusb_hotplug_event{
    LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = (1<<0), // 设备已插入,可以使用。
    LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT    = (1<<1)  // 设备已离开,不再可用。
}

// 热插拔标志
enum libusb_hotplug_flag{
    LIBUSB_HOTPLUG_ENUMERATE = (1<<0) // 枚举所有已插入的设备,若匹配也触发回调。
}

// 匹配标志
#define LIBUSB_HOTPLUG_NO_FLAGS   0 // 不使用任何标志
#define LIBUSB_HOTPLUG_MATCH_ANY -1 // 匹配所有

// 回调函数
typedef int (*libusb_hotplug_callback_fn)(
    libusb_context       *ctx,      // libusb环境上下文
    libusb_device        *device,   // 发生事件的设备
    libusb_hotplug_event  event,    // 插入或拔出事件
    void                 *user_data // 用户数据。
);

void libusb_hotplug_deregister_callback(libusb_context *ctx, libusb_hotplug_callback_handle callback_handle);
取消热插拔回调的注册。

void* libusb_hotplug_get_user_data(libusb_context *ctx, libusb_hotplug_callback_handle callback_handle);
获取与热插拔回调关联的用户数据。
用户数据就是 *user_data 参数所指数据。

代码举例:

/*
先检查是否支持热插拔。
    用 LIBUSB_CAP_HAS_HOTPLUG 参数来调用 libusb_has_capability() 以确认是否支持热插拔。
    libusb_context *libusbCtx = NULL;
    libusb_init(&libusbCtx);
    if(libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)){
        printf("支持热插拔\n");
    }
    libusb_exit(libusbCtx);

int libusb_hotplug_register_callback(libusb_context *ctx, ...);
    注册一个热插拔回调函数。

int libusb_hotplug_register_callback(
    libusb_context *ctx,        // libusb环境上下文
    int             events,     // 触发此回调的热插拔事件
    int             flags,      // 热插拔标志
    int             vendor_id,  // 要匹配的VID,  或设置为 LIBUSB_HOTPLUG_MATCH_ANY 来匹配所有。
    int             product_id, // 要匹配的PID,  或设置为 LIBUSB_HOTPLUG_MATCH_ANY 来匹配所有。
    int             dev_class,  // 要匹配的class,或设置为 LIBUSB_HOTPLUG_MATCH_ANY 来匹配所有。
    libusb_hotplug_callback_fn      cb_fn,          // 回调函数
    void                           *user_data,      // 传输给回调函数的用户数据。
    libusb_hotplug_callback_handle *callback_handle // 用于返回回调句柄。
);

// 触发回调的事件
enum libusb_hotplug_event{
    LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = (1<<0), // 设备已插入,可以使用。
    LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT    = (1<<1)  // 设备已离开,不再可用。
}

// 热插拔标志
enum libusb_hotplug_flag{
    LIBUSB_HOTPLUG_ENUMERATE = (1<<0) // 枚举所有已插入的设备,若匹配也触发回调。
}

// 匹配标志
#define LIBUSB_HOTPLUG_NO_FLAGS   0 // 不使用任何标志
#define LIBUSB_HOTPLUG_MATCH_ANY -1 // 匹配所有

// 回调函数
typedef int (*libusb_hotplug_callback_fn)(
    libusb_context       *ctx,      // libusb环境上下文
    libusb_device        *device,   // 发生事件的设备
    libusb_hotplug_event  event,    // 插入或拔出事件
    void                 *user_data // 用户数据。
);

void libusb_hotplug_deregister_callback(libusb_context *ctx, libusb_hotplug_callback_handle callback_handle);
    取消热插拔回调的注册。

void* libusb_hotplug_get_user_data(libusb_context *ctx, libusb_hotplug_callback_handle callback_handle);    
    获取与热插拔回调关联的用户数据。
    用户数据就是 *user_data 参数所指数据。
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "libusb.h"

static char* getLocalTimeString(void){
    static char buffer[32];
    struct tm localDate;
    time_t second = time(NULL);
    localtime_r(&second, &localDate);
    strftime(buffer, 30, "<%H:%M:%S>", &localDate);
    return buffer;
}

// 热插拔回调函数
static int hotplugCallback(
    libusb_context       *libusbCtx, 
    libusb_device        *dev, 
    libusb_hotplug_event  event, 
    void                 *userData
){
    uint8_t bus = libusb_get_bus_number(dev);
    uint8_t addr = libusb_get_device_address(dev);
    struct libusb_device_descriptor deviceDescriptor;
    memset(&deviceDescriptor, 0, sizeof(struct libusb_device_descriptor));
    libusb_get_device_descriptor(dev, &deviceDescriptor);
    
    // '+'表示插入,'-'表示拔出。
    printf("%s %c /dev/bus/usb/%03u/%03u %04x:%04x usb%u.%u class:%02x\n", 
        getLocalTimeString(), 
        (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED ? '+' : '-'),
        bus, addr, 
        deviceDescriptor.idVendor, 
        deviceDescriptor.idProduct, 
        (deviceDescriptor.bcdUSB & 0x0f00) >> 8, 
        (deviceDescriptor.bcdUSB & 0x00f0) >> 4, 
        deviceDescriptor.bDeviceClass
    );
    
    return 0;
}

int main(int argc, char* argv[]){
    // 设置等待事件的次数
    int eventCount = 30;
    if(argc >= 2){
        eventCount = atoi(argv[1]);
        if(eventCount >= 10000) eventCount = 10000;
        else if(eventCount < 1) eventCount = 1;
    }
    
    // 初始化libusb环境上下文
    libusb_context *libusbCtx = NULL;
    int errCode = libusb_init(&libusbCtx);
    if(errCode) return -1;
    
    // 检查是否支持热插拔
    if(libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)){
        printf("支持热插拔\n");
    }else{
        printf("不支持热插拔\n");
        libusb_exit(libusbCtx);
        return -2;
    }
    
    // 注册热插拔回调函数
    libusb_hotplug_callback_handle callbackHandle = 0;
    errCode = libusb_hotplug_register_callback(
        libusbCtx,                            // 环境上下文
        LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | // 插入事件
        LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,     // 拔出事件
        LIBUSB_HOTPLUG_ENUMERATE,             // 枚举已插入的设备
        LIBUSB_HOTPLUG_MATCH_ANY,             // 匹配所有VID
        LIBUSB_HOTPLUG_MATCH_ANY,             // 匹配所有PID
        LIBUSB_HOTPLUG_MATCH_ANY,             // 匹配所有CLass
        hotplugCallback,                      // 回调函数
        NULL,                                 // 调用回调函数时传递给回调函数的用户数据
        &callbackHandle                       // 返回回调句柄
    );
    if(errCode){
        printf("注册热插拔回调函数失败\n");
        libusb_exit(libusbCtx);
        return -3;
    }
    
    // 等待事件?
    while(eventCount-- > 0){
        libusb_handle_events_completed(libusbCtx, NULL);
    }
    
    // 取消热插拔回调
    libusb_hotplug_deregister_callback(libusbCtx, callbackHandle);
    libusb_exit(libusbCtx);
    return 0;
}
INCLUDE=-I/usr/include/libusb-1.0/
LIBDIR=-L/usr/lib/x86_64-linux-gnu/ -lusb-1.0

all: 
    gcc -o test1.exe test1.c $(INCLUDE) $(LIBDIR) -Wall
    gcc -o test2.exe test2.c $(INCLUDE) $(LIBDIR) -Wall
    gcc -o test3.exe test3.c $(INCLUDE) $(LIBDIR) -Wall
    gcc -o test4.exe test4.c $(INCLUDE) $(LIBDIR) -Wall

运行结果:

test@test-PC:~/TMP/libusb$ ./test4.exe 
支持热插拔
<14:56:07> + /dev/bus/usb/002/001 1d6b:0003 usb3.1 class:09
<14:56:07> + /dev/bus/usb/001/003 1c4f:0002 usb1.1 class:00
<14:56:07> + /dev/bus/usb/001/036 05e3:0610 usb2.1 class:09
<14:56:07> + /dev/bus/usb/001/004 093a:2510 usb2.0 class:00
<14:56:07> + /dev/bus/usb/001/001 1d6b:0002 usb2.0 class:09
<14:56:28> - /dev/bus/usb/001/036 05e3:0610 usb2.1 class:09
<14:56:29> + /dev/bus/usb/001/049 05e3:0610 usb2.1 class:09
<14:56:30> + /dev/bus/usb/001/050 0781:5567 usb2.0 class:00
<14:56:42> - /dev/bus/usb/001/004 093a:2510 usb2.0 class:00
<14:56:43> + /dev/bus/usb/001/051 093a:2510 usb2.0 class:00
<14:56:44> + /dev/bus/usb/001/052 096e:0209 usb1.1 class:00
<14:56:49> - /dev/bus/usb/001/052 096e:0209 usb1.1 class:00
<14:56:49> + /dev/bus/usb/001/053 058f:6387 usb2.0 class:00
<14:56:52> + /dev/bus/usb/001/054 096e:0209 usb1.1 class:00
<14:56:53> - /dev/bus/usb/001/050 0781:5567 usb2.0 class:00
<14:56:57> + /dev/bus/usb/001/055 0781:5567 usb2.0 class:00
<14:57:00> - /dev/bus/usb/001/053 058f:6387 usb2.0 class:00
<14:57:04> + /dev/bus/usb/001/056 058f:6387 usb2.0 class:00
<14:57:13> - /dev/bus/usb/001/054 096e:0209 usb1.1 class:00
<14:57:15> - /dev/bus/usb/001/055 0781:5567 usb2.0 class:00
<14:57:18> - /dev/bus/usb/001/056 058f:6387 usb2.0 class:00
<14:57:23> + /dev/bus/usb/001/057 0000:3825 usb1.1 class:00
<14:57:36> - /dev/bus/usb/001/057 0000:3825 usb1.1 class:00
<14:58:07> - /dev/bus/usb/001/051 093a:2510 usb2.0 class:00
<14:58:07> - /dev/bus/usb/001/049 05e3:0610 usb2.1 class:09
<14:58:11> + /dev/bus/usb/001/058 093a:2510 usb2.0 class:00
<14:59:11> + /dev/bus/usb/001/059 05e3:0610 usb2.1 class:09
<14:59:11> + /dev/bus/usb/001/060 096e:0209 usb1.1 class:00
<14:59:20> + /dev/bus/usb/001/061 0781:5567 usb2.0 class:00
<14:59:26> - /dev/bus/usb/001/060 096e:0209 usb1.1 class:00
<14:59:27> + /dev/bus/usb/001/062 096e:0209 usb1.1 class:00
<14:59:28> + /dev/bus/usb/001/063 096e:0209 usb1.1 class:00
<14:59:44> - /dev/bus/usb/001/063 096e:0209 usb1.1 class:00
<14:59:44> - /dev/bus/usb/001/062 096e:0209 usb1.1 class:00
<14:59:45> - /dev/bus/usb/001/061 0781:5567 usb2.0 class:00
test@test-PC:~/TMP/libusb$ 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容