You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Linux HCI命令中针对特定USB蓝牙适配器(指定厂商ID和产品ID)排除Read_Local_Extended_Features命令

如何在Linux HCI命令中针对特定USB蓝牙适配器(指定厂商ID和产品ID)排除Read_Local_Extended_Features命令

我完全理解你的困扰——UGREEN CM749蓝牙适配器在Linux 6.15.7内核下的初始化超时问题,全局注释Read_Local_Extended_Features虽然能解决,但会影响所有蓝牙设备,显然不是长期方案。下面是只针对特定VID/PID设备跳过该命令的上游友好修改方案,基于你提供的信息和内核蓝牙子系统的代码逻辑:

问题背景回顾

UGREEN CM749(VID 0x33fa,PID 0x0010)和CM748的行为与Linux内核的HCI初始化流程不兼容:内核发送Read_Local_Extended_Features后,紧接着发送Read_Buffer_Size,而适配器此时还未完成前一个命令的响应,导致后者超时。Windows 11会跳过对CM748的Read_Local_Extended_Features命令,我们可以对齐这个行为,只针对这两款设备做特殊处理。

核心修改思路

我们不需要全局修改初始化阶段的命令列表,而是在hci_read_local_ext_features_1_sync对应的底层函数中,添加USB VID/PID的判断逻辑:如果当前设备是目标UGREEN适配器,直接返回0(不执行该HCI命令),否则保持原有逻辑不变。

具体代码修改

修改内核源码net/bluetooth/hci_sync.c文件,步骤如下:

1. 添加USB头文件依赖

在文件顶部的#include区域添加:

#include <linux/usb.h>

2. 修改hci_read_local_ext_features_sync函数

找到你提到的hci_read_local_ext_features_sync函数,添加VID/PID判断逻辑:

static int hci_read_local_ext_features_sync(struct hci_dev *hdev, u8 page) {
    struct hci_cp_read_local_ext_features cp;
    struct usb_device *usb_dev;

    // 仅处理USB蓝牙设备,检查是否是目标UGREEN适配器
    if (hdev->dev && hdev->bus == HCI_USB) {
        usb_dev = to_usb_device(hdev->dev);
        // 匹配UGREEN CM749/CM748的VID和PID
        if (usb_dev->descriptor.idVendor == 0x33fa && 
            usb_dev->descriptor.idProduct == 0x0010) {
            BT_DBG("Skipping Read Local Extended Features for UGREEN CM749/CM748");
            return 0;
        }
    }

    // 原有逻辑:仅当设备支持扩展特性时才执行命令
    if (!lmp_ext_feat_capable(hdev))
        return 0;

    memset(&cp, 0, sizeof(cp));
    cp.page = page;

    return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES,
                                 sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}

替代方案:修改初始化阶段的命令列表

如果你更倾向于在初始化阶段直接跳过该命令,可以修改hci_init_stages数组,添加一个条件判断的初始化函数,替代原有的HCI_INIT(hci_read_local_ext_features_1_sync)项:

// 新增一个封装函数
static int hci_cond_read_local_ext_features_sync(struct hci_dev *hdev) {
    struct usb_device *usb_dev;

    if (hdev->dev && hdev->bus == HCI_USB) {
        usb_dev = to_usb_device(hdev->dev);
        if (usb_dev->descriptor.idVendor == 0x33fa && 
            usb_dev->descriptor.idProduct == 0x0010) {
            BT_DBG("Skipping Read Local Extended Features init for UGREEN device");
            return 0;
        }
    }

    // 非目标设备,执行原有命令
    return hci_read_local_ext_features_1_sync(hdev);
}

// 修改初始化阶段的数组项
static const struct hci_init_stage hci_init_stages[] = {
    // ... 其他初始化项 ...
    /* HCI_OP_READ_LOCAL_EXT_FEATURES */
    HCI_INIT(hci_cond_read_local_ext_features_sync),
    // ... 其他初始化项 ...
};

验证方法

  1. 编译并安装修改后的内核,重启系统
  2. 插入UGREEN CM749适配器,用lsusb确认设备被识别:
    lsusb | grep 33fa:0010
    
  3. 执行初始化命令,确认无超时错误:
    sudo hciconfig hci0 up
    
  4. 验证蓝牙功能正常:使用KDE/Plasma蓝牙守护进程或bluetoothctl扫描、连接设备

上游友好性说明

这种修改方案只针对特定VID/PID的设备做特殊处理,不会影响其他蓝牙适配器的正常工作,符合Linux内核的“quirk”(硬件兼容性特殊处理)设计原则。你可以基于这个修改提交补丁到蓝牙子系统,同时附上Windows的行为对比作为依据,这样被上游接受的概率会更高。

内容来源于stack exchange

火山引擎 最新活动