Ubuntu下libusb热插拔处理

Ubuntu下识别usb设备接入,使用libusb库;采用热插拔识别设备接入,并获取设备序列号。

1. 下载编译libusb库

安装依赖项

sudo apt install -y make dh-autoreconf

sudo apt install -y libudev-dev

编译后得到libusb-1.0.a与libusb-1.0.so, libusb.h

2. 程序基本流程

        初始化libusb:在main函数中,首先调用libusb_init初始化libusb上下文。

        检查热插拔支持:通过libusb_has_capability检查系统是否支持热插拔功能。

        注册回调函数:

                使用libusb_hotplug_register_callback注册设备接入回调函数hotplug_callback。
                同样使用该函数注册设备移除回调函数hotplug_callback_detach。

        事件循环:在while循环中,调用libusb_handle_events_timeout_completed处理libusb事件,超时5ms。注意不要使用libusb_handle_events,该接口会阻塞线程;

标准的示例处理设备如下所示,不过实际测试发现仅第一次接入设备能读取到设备序列后,后续就无法获取;猜测是设备重复插拔系统响应不过来,在设备接入时增加延时处理后热插拔OK!流程详见代码。 

  1. 设备接入处理(hotplug_callback):
    • 获取设备描述符。
    • 关闭之前打开的设备句柄(如果有)。
    • 打开新接入的设备。
    • 获取设备的序列号。
    • 配置设备接口,启用自动分离内核驱动,并尝试声明接口。
  2. 设备移除处理(hotplug_callback_detach):
    • 获取设备描述符。
    • 关闭打开的设备句柄(如果有)

#include "libusb.h"

#include <stdio.h>
#include <sys/time.h>
#include <bits/types.h>
#include <unistd.h>

int delaycnt = 0, iSerialNumber = 0;
libusb_device_handle *handle = NULL;
libusb_device *attach_dev    = NULL;

#define DEVICE_VID 0x1FC9
#define DEVICE_PID 0x0188

static int LIBUSB_CALL hotplug_callback(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data)
{
    (void)ctx;
    (void)dev;
    (void)event;
    (void)user_data;

    delaycnt   = 100;
    attach_dev = dev;

    return 0;
}

static int LIBUSB_CALL hotplug_callback_detach(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data)
{
    struct libusb_device_descriptor desc;
    int rc;

    (void)ctx;
    (void)dev;
    (void)event;
    (void)user_data;

    rc = libusb_get_device_descriptor(dev, &desc);
    if (LIBUSB_SUCCESS == rc) {
        printf ("Device detached: %04x:%04x\n", desc.idVendor, desc.idProduct);
    } else {
        printf ("Device detached\n");
        fprintf (stderr, "Error getting device descriptor: %s\n",
                libusb_strerror((enum libusb_error)rc));
    }

    if (handle) {
        libusb_close (handle);
        handle = NULL;
    }
    attach_dev = NULL;
    printf("attatch_dev NULL\n");

    return 0;
}

int main(void)
{
    libusb_hotplug_callback_handle hp[2];
    int rc;
    libusb_context *ctx;
    struct libusb_device_descriptor desc;

    rc = libusb_init(&ctx);
    if (LIBUSB_SUCCESS != rc)
    {
        printf ("failed to initialise libusb: %s\n",
               libusb_strerror((enum libusb_error)rc));
        return -1;
    }

    libusb_set_option(ctx, LIBUSB_OPTION_NO_DEVICE_DISCOVERY, 1);

    if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) {
        printf ("Hotplug capabilities are not supported on this platform\n");
        libusb_exit (NULL);
        return -1;
    }

    rc = libusb_hotplug_register_callback (ctx, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 1, DEVICE_VID,
                                          DEVICE_PID, LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, NULL, &hp[0]);
    if (LIBUSB_SUCCESS != rc) {
        fprintf (stderr, "Error registering callback 0\n");
        libusb_exit (NULL);
        return -1;
    }

    rc = libusb_hotplug_register_callback (ctx, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 1, DEVICE_VID,
                                          DEVICE_PID,LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback_detach, NULL, &hp[1]);
    if (LIBUSB_SUCCESS != rc) {
        fprintf (stderr, "Error registering callback 1\n");
        libusb_exit (NULL);
        return -1;
    }

    struct timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = 5000;

    while (1) {
        fflush(stdout);
        rc= libusb_handle_events_timeout_completed(ctx,&tv,NULL);
        if(rc!=LIBUSB_SUCCESS){
            printf("[lib_usb] libusb_handle_events error: %s\n", libusb_error_name(rc));
        }

        //device attached, delayed
        if(delaycnt > 0) {
            delaycnt--;
            if(delaycnt == 0) {
                printf("main thread get serial: %X\n", (int)attach_dev);
                rc = libusb_open (attach_dev, &handle);
                if (LIBUSB_SUCCESS != rc) {
                    fprintf (stderr, "No access to device: %s\n",
                            libusb_strerror((enum libusb_error)rc));
                }
                else {
                    printf("libusb open sucess\n");

                    rc = libusb_get_device_descriptor(libusb_get_device(handle), &desc);
                    if (LIBUSB_SUCCESS == rc) {
                        printf ("Device attached: %04x:%04x\n", desc.idVendor, desc.idProduct);
                    }
                    else {
                        printf ("Device attached: error getting device descriptor:%s\n", libusb_strerror((enum libusb_error)rc));
                    }

                    char serial[256] = {0};
                    libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber,
                                                       (uint8_t*)serial, sizeof(serial));
                    printf("device serial: %s, serialNumber:%d\n", serial, desc.iSerialNumber);

                    // 每次打开设备时配置接口
                    libusb_set_auto_detach_kernel_driver(handle, 1);//启用自动模式
                    int r = libusb_claim_interface(handle, 0);
                    if(r != LIBUSB_SUCCESS){
                        printf("libusb_claim_interface failed:%s\n", libusb_error_name(r));
                    }
                    if(r == LIBUSB_ERROR_BUSY) {
                        printf("lhandle detach\n");
                        libusb_detach_kernel_driver(handle, 0);    //手动立即解除绑定
                        libusb_claim_interface(handle, 0);
                    }
                }
            }
        }
    }

    if (handle) {
        libusb_close (handle);
    }

    libusb_exit (NULL);

    return 0;
}

运行日志如下:

main thread get serial: 35DACAE0
libusb open sucess
Device attached: 1fc9:0188
device serial: YU123456, serialNumber:3
Device detached: 1fc9:0188
attatch_dev NULL
main thread get serial: 48002460
libusb open sucess
Device attached: 1fc9:0188
device serial: YU123456, serialNumber:3

Device detached: 1fc9:0188
attatch_dev NULL
main thread get serial: 480037B0
libusb open sucess
Device attached: 1fc9:0188
device serial: YU123456, serialNumber:3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值