当前位置: 首页 > news >正文

Linux蓝牙协议栈驱动CSR8510 USB Dongle

 零.声明

本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下:

第一篇:蓝牙综合介绍 ,主要介绍蓝牙的一些概念,产生背景,发展轨迹,市面蓝牙介绍,以及蓝牙开发板介绍。

第二篇:Transport层介绍,主要介绍蓝牙协议栈跟蓝牙芯片之前的硬件传输协议,比如基于UART的H4,H5,BCSP,基于USB的H2等

第三篇:传统蓝牙controller介绍,主要介绍传统蓝牙芯片的介绍,包括射频层(RF),基带层(baseband),链路管理层(LMP)等

第四篇:传统蓝牙host介绍,主要介绍传统蓝牙的协议栈,比如HCI,L2CAP,SDP,RFCOMM,HFP,SPP,HID,AVDTP,AVCTP,A2DP,AVRCP,OBEX,PBAP,MAP等等一系列的协议吧。

第五篇:低功耗蓝牙controller介绍,主要介绍低功耗蓝牙芯片,包括物理层(PHY),链路层(LL)

第六篇:低功耗蓝牙host介绍,低功耗蓝牙协议栈的介绍,包括HCI,L2CAP,ATT,GATT,SM等

第七篇:蓝牙芯片介绍,主要介绍一些蓝牙芯片的初始化流程,基于HCI vendor command的扩展

第八篇:附录,主要介绍以上常用名词的介绍以及一些特殊流程的介绍等。

另外,开发板如下所示,对于想学习蓝牙协议栈的最好人手一套。以便更好的学习蓝牙协议栈,相信我,学完这一套视频你将拥有修改任何协议栈的能力(比如Linux下的bluez,Android下的bluedroid)。

-------------------------------------------------------------------------------------------------------------------------

蓝牙视频教程(跟韦东山老师合作):

https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22329603896.20.5aeb41f98e267j&id=693788592796

蓝牙交流扣扣群:765961169

Github代码:GitHub - sj15712795029/bluetooth_stack: 这是一个开源的双模蓝牙协议栈(bluetooth.stack)(btstack),可以运行在STM32,Linux.,包含HCI,L2CAP,SDP,RFCOMM,HFP,SPP,A2DP,AVRCP,AVDTP,AVCTP,OBEX,PBAP等协议,后续会继续维护,以达到商用的目的

入手开发板:https://shop220811498.taobao.com/category-1542116976.htm?spm=a1z10.5-c-s.w4010-22329603913.7.39ca7dbe2EA0K3&search=y&catName=%C0%B6%D1%C0%BF%AA%B7%A2%B0%E5#bd

蓝牙学习目录一篇文章足够你学习蓝牙技术,提供史上最全的蓝牙技术(传统蓝牙/低功耗蓝牙)文章总结,文档下载总结(2020/12/11更新)_Wireless_Link的博客-CSDN博客_蓝牙eir

--------------------------------------------------------------------------------------------------------------------------

本文的目的就是在ubuntu上驱动CSR8510,大概有两种做法:

  • 原生的linux默认免驱方式
  • 使用驱动方式(USB转tty) + 蓝牙协议栈方式来驱动
  • 使用libusb + 蓝牙协议栈方式来驱动

其中免驱方式我们已经在剖析Linux蓝牙子系统来驱动USB接口的蓝牙(CSR8510蓝牙dongle)原理-CSDN博客介绍过了,所以不再赘述,我们本文的目的是最后一种用libusb来驱动

一. CSR8510介绍

CSR8510 是 Qualcomm(高通)旗下CSR公司推出的一款 蓝牙无线通信芯片,主要应用于蓝牙适配器(USB Dongle)或嵌入式设备中,支持蓝牙数据传输和音频传输功能。以下是其关键信息:


1. 主要特性

  • 蓝牙版本:支持 蓝牙4.0(兼容蓝牙2.1+EDR、3.0、4.0 BLE),支持双模(经典蓝牙 + 低功耗蓝牙 BLE)。
  • 接口:集成 USB 2.0 控制器,可直接通过USB接口与主机设备(如PC、智能设备)连接。
  • 协议支持
    • 经典蓝牙协议:HID(键鼠)、A2DP(音频传输)、HFP(通话)、AVRCP(遥控)、SPP(串口)等。
    • 低功耗蓝牙(BLE):适用于物联网设备、传感器等低功耗场景。
  • 传输速率:理论最大速率 3 Mbps(EDR增强速率)。
  • 传输距离:约 10米(视环境干扰情况而定)。

2. 典型应用场景

  • 蓝牙适配器:用于为无蓝牙功能的电脑、电视等设备添加蓝牙连接能力。
  • 无线音频设备:连接蓝牙耳机、音箱,支持A2DP高品质音频传输。
  • 外设连接:无线键鼠、游戏手柄、打印机等(通过HID/SPP协议)。
  • 物联网(IoT):通过BLE与传感器、智能家居设备通信。

3. 技术优势

  • 低功耗:BLE模式显著降低能耗,适合电池供电设备。
  • 兼容性:广泛支持Windows、Linux、macOS等操作系统。
  • 集成度高:单芯片集成射频、基带和协议栈,简化设计。

4. 注意事项

  • 驱动依赖:在部分系统中(如Windows 10/11)可能需手动安装驱动。
  • 版本差异:不同厂商的CSR8510适配器可能阉割部分功能(如仅支持经典蓝牙,未启用BLE)。
  • 性能限制:蓝牙4.0的传输速率和延迟不如更新的蓝牙5.x,若需更高性能需选择新款芯片。

二. 卸载原生的驱动

目前有两种方式来禁用掉跟libusb的冲突

1. 卸载驱动方式

在Ubuntu系统中,CSR8510蓝牙适配器的驱动通常由内核模块(如 btusb)提供,属于系统默认集成的一部分。所以如果要做后两种方式,需要先把原生的免驱方式彻底屏蔽掉,也就是不让系统自动加载btusb驱动

a. 确认驱动信息

首先,确认系统是否已识别设备及当前加载的驱动:

lsmod | grep -i btusb

若输出显示 btusb 模块,则表明系统正使用该驱动。

b. 尝试临时卸载驱动

可临时移除 btusb 模块(需root权限):

sudo modprobe -r btusb

卸载后我们再查看btusb驱动已经不存在了

在这里我们就不用永久方式卸载btusb驱动了哈,风险比较大,有的小伙伴可能恢复不过来,所以我就不介绍了,但是只能告诉你们是可行的哈

2. libusb函数禁用到驱动

我们就直接上代码了哈,不用做更多的解释

if (libusb_kernel_driver_active(vnd_usb.dev_handle, 0) == 1) {
    result = libusb_detach_kernel_driver(vnd_usb.dev_handle, 0);
    if (result != 0) {
        ALOGE("libusb_detach_kernel_driver fail: %s", libusb_error_name(result));
        libusb_close(vnd_usb.dev_handle);
        libusb_exit(vnd_usb.usb_context);
        return;
    }
}

三. USB蓝牙的概念

Core spec定义如下

可以看到

hci command是用Control类型来控制,interface endpoint是0

hci event是用Interrupt类型来接收,interface endpoint是0x81

hci acl是用Bulk类型来收发数据,interface endpoint是0x82(IN),0x02(OUT)

hci sco是用isoch类型来收发数据,interface endpoint是0x83(IN),0x03(OUT)

HCI 数据类型

包类型标识

传输方向

USB 端点

libusb 函数

Command

0x01

Host→Dev

EP2 OUT (0x02)

libusb_control_transfer

Event

0x04

Dev→Host

EP1 IN (0x81)

libusb_interrupt_transfer

ACL Data

0x02

双向

EP2 OUT (0x02)/IN (0x82)

libusb_bulk_transfer

SCO Data

0x03

双向

(需确认是否支持)

libusb_isochronous_transfer

NOTED:需要注意的是H4跟H2出了uart跟usb的差异外,h2没有h4 transport的packet type哈,为啥呢?因为每种type都有EP地址,所以不需要,这个很好理解!

四. 使用libusb驱动

libusb是一个开源的、跨平台的用户态 USB 设备驱动库(USB host角色),允许开发者在不依赖操作系统内核驱动的情况下直接与 USB 设备通信。它广泛应用于嵌入式系统、逆向工程、数据采集、自定义设备控制等领域。

  • 跨平台支持
    • Linux / macOS / Windows / Android 等。
    • 统一 API,无需为不同平台编写不同代码。
  • 用户态驱动
    • 无需编写内核驱动,直接通过用户态程序操作 USB 设备。
    • 开发效率高,调试方便。
  • 异步 & 同步传输
    • 支持同步阻塞式操作(如 libusb_bulk_transfer)。
    • 提供异步非阻塞接口(如 libusb_submit_transfer),适合高性能场景。
  • 设备枚举与管理
    • 支持 USB 设备发现、打开、关闭、配置接口等。
    • 获取设备描述符(厂商 ID、产品 ID、序列号等)。
  • 传输模式
    • 控制传输(Control Transfer):用于设备配置(如 libusb_control_transfer)。
    • 批量传输(Bulk Transfer):大数据量传输(如文件读写)。
    • 中断传输(Interrupt Transfer):实时性要求高的场景(如 HID 设备)。
    • 等时传输(Isochronous Transfer):音视频流传输(需硬件支持)。

我们就是用libusb来驱动CSR8510

整个架构包含以下组件:

  • 蓝牙协议栈:这个不用做过多解释哈·
  • libusb:这个充当usb host角色,直接用libusb来操作usb设备,不需要内核介入
  • CSR8510:蓝牙dongle

下面我们就来说明下来驱动csr8510的步骤吧

1. libusb的初始化

libusb_context *usb_context;

result = libusb_init(&vnd_usb.usb_context);
if (result < 0) {
    ALOGE("usb_vendor_open fail: %s", libusb_error_name(result));
    return;
}

libusb_initlibusb 库的初始化函数,用于创建并初始化 libusb 的上下文(Context)。它是所有 libusb 操作的起点,必须在调用其他 libusb 函数前执行。以下是详细解释:

函数原型

int libusb_init(libusb_context **ctx);

参数

  • ctx:指向 libusb_context 指针的指针。如果传入 NULL,libusb 会使用默认的全局上下文;如果传入非 NULL 的指针地址,则会创建独立的上下文(适用于多线程或复杂场景)。

返回值

  • LIBUSB_SUCCESS (0):初始化成功。
  • 负数:错误码(如内存不足、权限问题等)。

2. libusb匹配特定的usb设备(csr8510)

libusb_device_handle *dev_handle;

vnd_usb.dev_handle = libusb_open_device_with_vid_pid(vnd_usb.usb_context, CSR8510_USB_VID, CSR8510_USB_PID);
if (!vnd_usb.dev_handle) {
    ALOGE("usb_vendor_open can not find 0x%04x:0x%04x device",CSR8510_USB_VID,CSR8510_USB_PID);
    libusb_exit(vnd_usb.usb_context);
    return;
}

libusb_open_device_with_vid_pidlibusb 库中的一个便捷函数,用于通过 厂商ID(VID)产品ID(PID) 快速打开匹配的 USB 设备。它简化了设备发现和初始化的流程,适用于已知目标设备 VID/PID 的场景。

函数原型

libusb_device_handle* libusb_open_device_with_vid_pid(
    libusb_context* ctx,      // libusb 上下文(通常填 NULL)
    uint16_t vendor_id,       // 设备厂商ID(VID)
    uint16_t product_id       // 设备产品ID(PID)
);

参数

  • ctx:libusb 上下文指针。传入 NULL 表示使用默认全局上下文。
  • vendor_id:目标设备的 16 位厂商 ID(VID),例如 0x1234
  • product_id:目标设备的 16 位产品 ID(PID),例如 0x5678

返回值

  • 成功:返回已打开的 USB 设备句柄(libusb_device_handle*)。
  • 失败:返回 NULL(设备未找到或打开失败)。

其中csr8510的vid/pid定义如下:

#define CSR8510_USB_VID 0x0a12
#define CSR8510_USB_PID 0x0001

我们是通过lsusb来查看的哈

3. libusb卸载内核驱动

if (libusb_kernel_driver_active(vnd_usb.dev_handle, 0) == 1) {
    result = libusb_detach_kernel_driver(vnd_usb.dev_handle, 0);
    if (result != 0) {
        ALOGE("libusb_detach_kernel_driver fail: %s", libusb_error_name(result));
        libusb_close(vnd_usb.dev_handle);
        libusb_exit(vnd_usb.usb_context);
        return;
    }
}

a. libusb_kernel_driver_active

功能

  • 检测内核驱动是否绑定了设备的某个接口
  • 当操作系统内核已为 USB 设备的某个接口加载了驱动(例如 USB 串口驱动、HID 驱动等),用户态程序需要通过此函数确认驱动状态。

原型

int libusb_kernel_driver_active(libusb_device_handle *dev_handle, int interface_number);

参数

  • dev_handle:已打开的 USB 设备句柄。
  • interface_number:要检查的接口编号(通常为 0, 1, 2...)。

返回值

  • 1:内核驱动已绑定该接口。
  • 0:内核驱动未绑定。
  • 负数:错误码(如 LIBUSB_ERROR_NO_DEVICE 表示设备已断开)。

b. libusb_detach_kernel_driver

功能

  • 解除内核驱动对 USB 设备接口的绑定
  • 用户态程序需要通过此函数释放内核驱动对接口的控制权,才能通过 libusb 直接操作设备。

原型

int libusb_detach_kernel_driver(libusb_device_handle *dev_handle, int interface_number);

参数

  • dev_handle:已打开的 USB 设备句柄。
  • interface_number:要解除绑定的接口编号。

返回值

  • 0:成功解除绑定。
  • 负数:错误码(如 LIBUSB_ERROR_NOT_FOUND 表示驱动未绑定)。

4. libusb发现usb interface/声明

其中发现usb interface是可选的操作,正常你如果想做成一个通用的,鉴于不同的芯片USB EP addr可能有细微差异,所以正常应该需要扫描USB EP addr,但是我们csr8510是固定的,所以我们就不做这个工作了,但是声明还是要做的,我们来看下代码

result = libusb_claim_interface(vnd_usb.dev_handle, 0);
	if (result < 0) {
	    ALOGE("libusb_claim_interface: %s", libusb_error_name(result));
	    libusb_close(vnd_usb.dev_handle);
	    libusb_exit(vnd_usb.usb_context);
        return;
	}

我们来介绍下libusb_claim_interface函数

功能

  • 声明对 USB 设备某个接口的独占访问权
  • 在操作 USB 设备前,必须通过此函数声明要使用的接口(Interface),否则无法进行数据传输。

原型

int libusb_claim_interface(libusb_device_handle *dev_handle, int interface_number);

参数

  • dev_handle:已打开的 USB 设备句柄。
  • interface_number:接口编号(通常为 0, 1, 2...,根据设备描述符确定)。

返回值

  • 0:成功声明接口。
  • 负数:错误码(如 LIBUSB_ERROR_BUSY 表示接口已被占用)。

关键作用

  • 解除内核驱动占用(Linux 特有):
    在调用前需确保内核驱动已解除绑定(通过 libusb_detach_kernel_driver)。
  • 独占访问
    同一时刻只能有一个程序(或线程)操作该接口。
  • 资源管理
    必须与 libusb_release_interface 配对使用。

5. libusb发送hci command/acl数据

a. 发送hci command

void send_hci_command_packet(uint8_t *data, int32_t len) 
{
    int retry_count = 0;
    int result = 0;
    const char* func_name = __func__;

    do {
        result = libusb_control_transfer(vnd_usb.dev_handle,
                    LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
                    0x00, 0x0000, 0x0000, data, len, 1000);

        if (result >= 0) {
            if (result == len) {
                return;
            }
            ALOGW("%s: Partial transfer: sent %d/%d bytes (retry %d/%d)", 
                 func_name, result, len, retry_count+1, MAX_RETRY_ATTEMPTS);
            result = LIBUSB_ERROR_IO;
        } else {
            ALOGW("%s: Attempt %d/%d failed: %s (%d)", 
                 func_name, retry_count+1, MAX_RETRY_ATTEMPTS,
                 libusb_error_name(result), result);
        }

        if (result == LIBUSB_ERROR_NO_DEVICE || 
            result == LIBUSB_ERROR_NOT_FOUND ||
            result == LIBUSB_ERROR_ACCESS) {
            break;
        }

        if (retry_count < MAX_RETRY_ATTEMPTS) {
            usleep(RETRY_DELAY_MS * 1000);
        }
    } while (retry_count++ < MAX_RETRY_ATTEMPTS);

    ALOGE("%s: Failed after %d attempts: %s (%d), last sent %d/%d bytes",
         func_name, retry_count, libusb_error_name(result), result, (result > 0) ? result : 0, len);
}

我们发送hci comamnd主要通过libusb_control_transfer函数,下面我们来介绍下这个函数的功能

功能

  • 执行 USB 控制传输(Control Transfer)
  • 控制传输用于设备配置、命令发送、状态查询等,是 USB 协议中的基础传输类型。

原型

int libusb_control_transfer(
    libusb_device_handle *dev_handle,
    uint8_t bmRequestType,  // 请求类型(方向/类型/接收方)
    uint8_t bRequest,        // 请求码(如 GET_DESCRIPTOR)
    uint16_t wValue,         // 请求参数(根据请求码定义)
    uint16_t wIndex,         // 接口/端点索引(根据请求码定义)
    unsigned char *data,     // 数据缓冲区
    uint16_t wLength,        // 数据长度
    unsigned int timeout     // 超时时间(毫秒)
);

返回值

  • 成功:实际传输的字节数。
  • 失败:负数错误码(如 LIBUSB_ERROR_TIMEOUT)。

典型用途

  • 获取设备描述符(如 GET_DESCRIPTOR 请求)。
  • 设置设备配置(如 SET_CONFIGURATION)。
  • 发送厂商自定义命令(Vendor-Specific Commands)。

b. 发送hci acl

void send_hci_acl_packet(uint8_t *data, int32_t len) 
{
    int retry_count = 0;
    int32_t transferred = 0;
    int result = 0;
    const char* func_name = __func__;

    do {
        result = libusb_bulk_transfer(vnd_usb.dev_handle, 
                    BT_USB_ACL_OUT_EP_ADDR, data, len, 
                    &transferred, 1000);

        if (result == LIBUSB_SUCCESS) {
            if (transferred == len) {
                return;
            }
            ALOGW("%s: Partial transfer: sent %d/%d bytes (retry %d/%d)", 
                 func_name, transferred, len, retry_count+1, MAX_RETRY_ATTEMPTS);
            result = LIBUSB_ERROR_IO;
        } else {
            ALOGW("%s: Attempt %d/%d failed: %s (%d)", 
                 func_name, retry_count+1, MAX_RETRY_ATTEMPTS,
                 libusb_error_name(result), result);
        }

        switch (result) {
            case LIBUSB_ERROR_PIPE:
                libusb_clear_halt(vnd_usb.dev_handle, BT_USB_ACL_OUT_EP_ADDR);
                break;
            case LIBUSB_ERROR_NO_DEVICE:
            case LIBUSB_ERROR_NOT_FOUND:
                goto final_error;
        }

        if (retry_count < MAX_RETRY_ATTEMPTS) {
            usleep(RETRY_DELAY_MS * 1000);
        }
    } while (retry_count++ < MAX_RETRY_ATTEMPTS);

final_error:
    ALOGE("%s: Failed after %d attempts: %s (%d), last sent %d/%d bytes",
         func_name, retry_count, libusb_error_name(result), result, transferred, len);
}

我们发送hci acl数据主要通过libusb_bulk_transfer这个函数,下面我们来介绍下这个函数的功能

功能

  • 执行 USB 批量传输(Bulk Transfer)
  • 批量传输用于可靠的大数据量传输(如文件读写),无实时性要求但保证数据完整性。

原型

int libusb_bulk_transfer(
    libusb_device_handle *dev_handle,
    unsigned char endpoint,  // 端点地址(含方向,如 0x81 表示 IN 端点)
    unsigned char *data,     // 数据缓冲区
    int length,              // 数据长度
    int *transferred,        // 实际传输的字节数(输出参数)
    unsigned int timeout     // 超时时间(毫秒)
);

返回值

  • 0:传输成功。
  • 负数:错误码(如 LIBUSB_ERROR_PIPE 表示端点错误)。

关键特性

  • 方向标识
    端点地址的最高位表示方向(0x80 表示 IN,0x00 表示 OUT)。
  • 可靠性
    数据传输保证完整性,出错时会重试。
  • 大块数据
    适合传输文件、固件等大数据块。

6. libusb接收hci event/acl数据

libusb有同步跟异步接收数据的方式,同步方式比较简单,就是while loop一直读取event跟acl数据就可以了,但是这种方式对于实时性无法得到保证,对于播放音乐的场景就比较局限,所以我们直接采取异步方式了,我们先来看下event跟acl的EP

所以我们直接贴代码

typedef struct {
    struct libusb_transfer* event_transfer;
    struct libusb_transfer* acl_transfer;
    bool async_transfer_running;
    pthread_mutex_t lock;
} async_usb_ctx_t;

static void async_transfer_cb(struct libusb_transfer* transfer)
{
	int result;
	async_usb_ctx_t* ctx = (async_usb_ctx_t*)transfer->user_data;

	if (transfer->status == LIBUSB_TRANSFER_STALL){
		ALOGE("Transfer stalled, trying again");
        result = libusb_clear_halt(vnd_usb.dev_handle, transfer->endpoint);
        if (result) {
            ALOGE("libusb_clear_halt fail: %s", libusb_error_name(result));
        }
        result = libusb_submit_transfer(transfer);
        if (result) {
			ALOGE("re-submitting transfer fail: %s", libusb_error_name(result));
        }
    }

	if(transfer->status == LIBUSB_TRANSFER_COMPLETED)
	{
		if(transfer->endpoint == BT_USB_EVENT_EP_ADDR)
		{
			uint8_t pkt_with_type[transfer->actual_length + 1];
			pkt_with_type[0] = HCI_EVENT_PKT;
			memcpy(pkt_with_type + 1, transfer->buffer, transfer->actual_length);
			
			write(((osi_serial_i_t*)vnd_usb.vendor_fd)->fd, pkt_with_type, transfer->actual_length + 1);
		}
		else if(transfer->endpoint == BT_USB_ACL_IN_EP_ADDR)
		{
			uint8_t pkt_with_type[transfer->actual_length + 1];
	        pkt_with_type[0] = HCI_ACLDATA_PKT;
	        memcpy(pkt_with_type + 1, transfer->buffer, transfer->actual_length);
	        
	        write(((osi_serial_i_t*)vnd_usb.vendor_fd)->fd,pkt_with_type,transfer->actual_length + 1);
		}
	}
	
	pthread_mutex_lock(&ctx->lock);
	if (ctx->async_transfer_running) {
		libusb_submit_transfer(transfer);
	}
	pthread_mutex_unlock(&ctx->lock);

}

async_usb_ctx_t* async_usb_init(libusb_device_handle* dev_handle) {
    async_usb_ctx_t* ctx = calloc(1, sizeof(async_usb_ctx_t));
    if (!ctx) return NULL;

    ctx->event_transfer = libusb_alloc_transfer(0);
    if (!ctx->event_transfer) goto error;
    
    ctx->acl_transfer = libusb_alloc_transfer(0);
    if (!ctx->acl_transfer) goto error;

    libusb_fill_interrupt_transfer(
        ctx->event_transfer,
        dev_handle,
        BT_USB_EVENT_EP_ADDR,
        data_recv,
        sizeof(data_recv),
        async_transfer_cb,
        ctx,
        100
    );

    libusb_fill_bulk_transfer(
        ctx->acl_transfer,
        dev_handle,
        BT_USB_ACL_IN_EP_ADDR,
        data_recv,
        sizeof(data_recv),
        async_transfer_cb,
        ctx,
        100
    );

    pthread_mutex_init(&ctx->lock, NULL);
    return ctx;

error:
    if (ctx->event_transfer) libusb_free_transfer(ctx->event_transfer);
    if (ctx->acl_transfer) libusb_free_transfer(ctx->acl_transfer);
    free(ctx);
    return NULL;
}

void async_usb_start(async_usb_ctx_t* ctx) {
    pthread_mutex_lock(&ctx->lock);
    ctx->async_transfer_running = true;
    
    int result = libusb_submit_transfer(ctx->event_transfer);
    if (result != LIBUSB_SUCCESS) {
        ALOGE("libusb_submit_transfer fail: %s", libusb_error_name(result));
    }

    result = libusb_submit_transfer(ctx->acl_transfer);
    if (result != LIBUSB_SUCCESS) {
        ALOGE("libusb_submit_transfer fail: %s", libusb_error_name(result));
    }
    pthread_mutex_unlock(&ctx->lock);
}


void async_usb_stop(async_usb_ctx_t* ctx) {
    pthread_mutex_lock(&ctx->lock);
    ctx->async_transfer_running = false;
    
    if (ctx->event_transfer) {
        libusb_cancel_transfer(ctx->event_transfer);
    }
    if (ctx->acl_transfer) {
        libusb_cancel_transfer(ctx->acl_transfer);
    }
    pthread_mutex_unlock(&ctx->lock);
}

void async_usb_cleanup(async_usb_ctx_t* ctx) {
    async_usb_stop(ctx);
    
    libusb_free_transfer(ctx->event_transfer);
    libusb_free_transfer(ctx->acl_transfer);
    pthread_mutex_destroy(&ctx->lock);
    free(ctx);
}

然后在接收线程中使用while loop来监听

while (vnd_usb.u2s_thread_runing) {

		struct timeval tv = {0, 100000}; // 100ms
    	libusb_handle_events_timeout_completed(NULL, &tv, NULL);
		
    }

我们来解释下其中用到的各个API

a. libusb_alloc_transfer

功能

  • 分配并初始化一个异步传输结构体libusb_transfer)。
  • 用于准备异步传输(如批量、中断、控制或等时传输)所需的内存资源。

原型

struct libusb_transfer* libusb_alloc_transfer(int iso_packets);

参数

  • iso_packets:等时传输(Isochronous Transfer)的包数量,非等时传输填 0

返回值

  • 成功:指向 libusb_transfer 结构体的指针。
  • 失败:NULL(内存不足)。

b. libusb_fill_interrupt_transfer

功能

  • 填充中断传输(Interrupt Transfer)参数libusb_transfer 结构体。
  • 用于配置中断端点的异步传输。

原型

void libusb_fill_interrupt_transfer(
    struct libusb_transfer *transfer,  // 已分配的传输结构体
    libusb_device_handle *dev_handle,  // 设备句柄
    unsigned char endpoint,            // 端点地址(含方向)
    unsigned char *buffer,             // 数据缓冲区
    int length,                        // 缓冲区长度
    libusb_transfer_cb_fn callback,    // 传输完成回调函数
    void *user_data,                   // 用户自定义数据(传递给回调)
    unsigned int timeout               // 超时时间(毫秒)
);

c. libusb_fill_bulk_transfer

功能

  • 填充批量传输(Bulk Transfer)参数libusb_transfer 结构体。
  • 用于配置批量端点的异步传输。

原型

void libusb_fill_bulk_transfer(
    struct libusb_transfer *transfer,
    libusb_device_handle *dev_handle,
    unsigned char endpoint,
    unsigned char *buffer,
    int length,
    libusb_transfer_cb_fn callback,
    void *user_data,
    unsigned int timeout
);

d. libusb_submit_transfer

功能

  • 提交异步传输请求到 libusb 事件系统。
  • 传输将在后台执行,完成后触发回调函数。

原型

int libusb_submit_transfer(struct libusb_transfer *transfer);

返回值

  • 0:提交成功。
  • 负数:错误码(如 LIBUSB_ERROR_NO_DEVICE 设备已断开)。

e. libusb_cancel_transfer

功能

  • 取消已提交但未完成的传输
  • 若传输正在进行中,会尝试终止传输并触发回调函数。

原型

int libusb_cancel_transfer(struct libusb_transfer *transfer);

返回值

  • 0:取消请求已提交(不保证传输立即停止)。
  • 负数:传输已完成或已取消。

f. libusb_free_transfer

功能

  • 释放由 libusb_alloc_transfer 分配的传输结构体
  • 必须在传输完成或取消后调用,否则会导致内存泄漏。

原型

void libusb_free_transfer(struct libusb_transfer *transfer);

g. 关键注意事项

生命周期管理

    • 传输结构体必须在回调中或明确取消后释放。
    • 缓冲区内存需在传输期间保持有效。

线程安全

    • 异步操作依赖事件循环线程,需确保 libusb_handle_events/libusb_handle_events_timeout_completed 在独立线程运行。
    • 回调函数中避免阻塞操作。

错误处理

    • 在回调中检查 transfer->status
    • 处理 LIBUSB_TRANSFER_CANCELLEDLIBUSB_TRANSFER_ERROR 状态。

性能优化

    • 批量传输适合大数据量,中断传输适合小数据实时传输。
    • 使用多个并发的传输结构体提高吞吐量。

h. 函数对比总结

函数

作用

调用时机

libusb_alloc_transfer

分配传输结构体

传输开始前

libusb_fill_*_transfer

配置传输参数

提交传输前

libusb_submit_transfer

提交异步请求

参数配置完成后

libusb_cancel_transfer

取消进行中的传输

需要提前终止传输时

libusb_free_transfer

释放传输结构体

传输完成或取消后

掌握这些 API 可实现高性能、非阻塞的 USB 通信,适用于实时数据采集或低延迟控制场景。

相关文章:

  • Sqoop常用指令
  • 黑马点评 秒杀优惠券单体下一人一单超卖问题
  • spring cloud gateway 转发 ws 流量
  • 【3GPP】【5G】精讲5G系统的策略和计费控制框架
  • 【MySQL从入门到精通】之基础概念详解
  • 多版本go冲突问题
  • 数据结构-哈希表
  • 免费送源码:Java+ssm+MySQL 酒店预订管理系统的设计与实现 计算机毕业设计原创定制
  • 社交电商引流策略中的让利行为及其影响——基于开源AI智能名片、链动2+1模式与S2B2C商城小程序的分析
  • Spring Boot 热部署详解,包含详细的配置项说明
  • 行业标准 | IT服务技术与标准研讨会在京召开
  • Qt文件读写
  • AMGCL库的Backends及使用示例
  • Java基础:Stream流操作
  • 【软考系统架构设计师】信息安全技术基础知识点
  • 25级总分413数学一142专业124东南大学820考研经验电子信息通信工程,真题,大纲,参考书。
  • 开源模型应用落地-qwen模型小试-Qwen2.5-7B-Instruct-tool usage入门-集成心知天气(二)
  • 深入理解 HTML5 语义元素:提升网页结构与可访问性
  • 【C++】中memcpy的使用
  • 校园AI体育:科技赋能教育,运动点亮未来
  • 世界疫情最新消息数据/汕头seo公司
  • 益阳一站式网站建设公司/网络推广运营公司
  • 贵州网站推广公司/视频网站建设
  • 网站流量平台/如何进行网络营销策划
  • 哪些网站做免费送东西的广告/seo攻略
  • 网站的想法/aso安卓优化公司