基于 OpenHarmony 6.1 Release

1. 适配背景与目标

本文以 mp_hi3781v735 平台 为例,介绍在 OpenHarmony 6.1 Release 系统中适配 兆通微 9612U USB 蓝牙模组 的过程。

蓝牙模组本身只是一个硬件设备。将其接入开发板后,系统并不能天然识别和使用该模组,需要通过驱动和适配层完成硬件与操作系统之间的衔接。驱动适配的核心目标是让系统能够正确完成以下动作:

  • 发现蓝牙 USB 设备;
  • 加载对应内核驱动;
  • 初始化蓝牙 HCI 通路;
  • 向 OpenHarmony 蓝牙协议栈提供统一访问接口;
  • 支持上层应用通过标准蓝牙 API 使用蓝牙功能。

本次适配主要包括三个部分:

  1. 编译并加载 USB 蓝牙内核驱动 ztop_bt_usb.ko
  2. 集成蓝牙 Vendor 适配层 libbt_vendor.so
  3. 修改 OpenHarmony 系统配置,使驱动和适配库随系统镜像一同编译、打包和加载。

2. USB 蓝牙内核驱动适配

2.1 .ko 内核模块的作用

.ko 是 Linux Kernel Object 的缩写,即 Linux 内核模块。它允许开发者在系统运行时动态加载一段内核态代码,而无需重新编译完整内核。

在本案例中,兆通微提供的 USB 蓝牙驱动最终会编译生成:

ztop_bt_usb.ko

该模块负责完成 USB 蓝牙芯片和 Linux 内核之间的对接,使内核能够识别并驱动 9612U 蓝牙模组。

2.2 ztop_bt_usb.ko 的功能定位

ztop_bt_usb.ko 的主要作用是建立底层硬件访问通路。它位于内核空间,向上承接蓝牙 HCI 数据传输需求,向下控制 USB 蓝牙设备。

简单来说,它解决的是:

系统内核如何识别并驱动这个 USB 蓝牙模组。

在整体蓝牙架构中,ztop_bt_usb.ko 并不直接面向应用层,而是为用户空间的 Vendor 适配库和蓝牙协议栈提供底层能力。


3. 编译 ztop_bt_usb.ko

3.1 编译环境准备

模组厂商提供的驱动源码放置在项目根目录下:

ZTOP/

其中,内核驱动源码目录为:

ZTOP/bt_driver/bt_driver

本次驱动编译的大致调用链如下:

build_log_parse.sh
    -> Makefile
        -> make_helpers/build_plat/*.mk
            -> ztop_bt_usb.ko

其中,make_helpers/build_plat/*.mk 是不同平台的编译参数配置文件,是本次适配中需要重点关注的部分。


3.2 平台配置文件

平台定义文件位于:

make_helpers/build_plat/*.mk

适配新平台时,需要参考厂商已有平台的 .mk 文件,新增或修改对应平台配置。本案例中新增或调整的是 hi3781v735 平台相关配置。

需要重点确认以下参数:

参数 含义 mp_hi3781v735 示例
ARCH CPU 架构 arm64
CROSS_COMPILE 交叉编译器前缀 aarch64-v100-linux-
KVER 目标板内核版本 5.10.210-shaolingun+
KSRC 内核编译产物目录 out/shaolingun/obj/KERNEL_OBJ_D
OS_TYPE 系统类型 OS_ANDROIDOS_LINUX
BUILD_ARGS 编译器及构建参数 V=$(V) LLVM=$(LLVM) CC=$(CC) LD=$(LD)

img


其中,KVER 应与开发板上的内核版本保持一致,可通过以下命令确认:

uname -r

KSRC 需要指向编译机上的内核编译产物目录,并且该目录下应存在 .config 文件:

ls out/shaolingun/obj/KERNEL_OBJ_D/.config

如果 KVERKSRC 配置错误,通常会导致模块编译失败,或者编译出的 .ko 文件无法在目标板上加载。

上述参数对应Makefile 文件中

img

3.3 编译入口脚本

驱动编译入口脚本为:

build_log_parse.sh

该脚本接收三个核心参数:

  • product:产品类型;
  • interface:接口类型;
  • build-plat:构建平台,对应 .mk 平台配置文件。

本案例中可执行以下命令:

./build_log_parse.sh --product=zt9612 --interface=usb --build-plat=hi3781v735

由于厂商脚本中已设置默认产品和接口参数,如果默认值与本次目标一致,也可以简化为:

./build_log_parse.sh --build-plat=hi3781v735

编译成功后,应生成目标内核模块:

ztop_bt_usb.ko

4. 系统启动阶段自动加载驱动

4.1 init 配置文件

为了让系统启动时自动加载蓝牙 USB 驱动,需要修改平台 init 配置文件:

vendor/hisilicon/mp_hi3781v735/image_cfg/system/cfg/init.shaolingun.cfg

该文件中的 pre-initinitfsboot 等字段代表系统启动过程中的不同阶段。init 进程会在不同阶段执行对应的命令。


4.2 fs 阶段配置

fs 阶段通常用于执行文件系统准备、驱动模块加载、设备节点初始化等操作。

本次适配中,核心命令为:

insmod /vendor/etc/bluetooth/ztop_bt_usb.ko

该命令用于加载兆通微 USB 蓝牙内核驱动。

同时,还需要配置相关设备节点权限,例如:

chown bluetooth bluetooth /dev/uhid

/dev/uhid 是用户态 HID 设备接口,蓝牙 HID 相关功能可能依赖该节点。


4.3 boot 阶段配置

boot 阶段一般用于系统启动后期的权限配置、服务运行环境准备等。

本次涉及的典型配置包括:

chown blue_host blue_host /sys/class/rfkill/rfkill0/state

chown bluetooth bluetooth /dev/tun

其中:

  • /sys/class/rfkill/rfkill0/state 用于控制无线设备开关状态;
  • /dev/tun 用于虚拟网络设备访问,部分蓝牙网络相关功能可能依赖该节点。

img


需要说明的是,本次适配属于系统版本升级适配,部分原有权限配置如 07770775 存在权限过宽的问题。为了降低版本升级带来的行为差异,本次暂未调整这些历史配置,但后续正式产品化时建议结合安全规范进一步收敛权限。


5. 蓝牙 Vendor 适配层集成

5.1 Vendor 适配层的作用

蓝牙 Vendor 适配层位于 OpenHarmony 蓝牙 HDI Service 与底层蓝牙硬件之间,核心产物为:

libbt_vendor.so

它本质上是一个蓝牙 HCI 传输层适配库,用于屏蔽底层模组差异。

上层 HDI Service 只需要通过统一接口调用:

  • init()
  • op()
  • close()

至于底层使用 USB 还是 UART、H4 还是 H5 协议,则由 Vendor 适配层负责处理。

在本案例中,厂商提供的 Vendor 适配层源码位于:

ZTOP/bt_driver/code/libbt-vendor

5.2 创建蓝牙部件目录

在 OpenHarmony 工程中创建蓝牙适配目录:

device/board/hisilicon/shaolingun/bluetooth

将厂商源码中的以下目录复制到该目录下:

codec
include
src

同时创建配置目录:

device/board/hisilicon/shaolingun/bluetooth/cfg

并将以下文件复制到 cfg 目录:

ztop_bt_usb.ko
ztopbt.conf

最终目录结构示例如下:

device/board/hisilicon/shaolingun/bluetooth
├── BUILD.gn
├── cfg
│   ├── ztop_bt_usb.ko
│   └── ztopbt.conf
├── codec
├── include
└── src

6. 配置 OpenHarmony 编译系统

6.1 编写 BUILD.gn

在以下路径创建 BUILD.gn 文件:

device/board/hisilicon/shaolingun/bluetooth/BUILD.gn

该文件主要完成三件事:

  1. 定义蓝牙构建组 bt_group
  2. ztop_bt_usb.koztopbt.conf 预置到系统镜像;
  3. 编译生成 libbt_vendor 动态库。

示例配置如下:

import("//build/ohos.gni")

group("bt_group") {
  deps = [
    ":ztop_bt_usb",
    ":ztopbt.conf",
    ":libbt_vendor",
  ]
}

config("bt_warnings") {
  cflags = [
    "-Wall",
    "-Werror",
    "-Wno-unused-but-set-variable",
    "-Wno-switch",
    "-Wno-unused-function",
    "-Wno-unused-parameter",
    "-Wno-unused-variable",
    "-Wno-implicit-function-declaration",
    "-Wno-incompatible-pointer-types",
    "-Wno-ignored-attributes",
    "-Wno-misleading-indentation",
  ]
}

ohos_prebuilt_etc("ztop_bt_usb") {
  source = "cfg/ztop_bt_usb.ko"
  install_enable = true
  install_images = [ chipset_base_dir ]
  subsystem_name = "device_shaolingun"
  part_name = "device_shaolingun"
  relative_install_dir = "./bluetooth"
}

ohos_prebuilt_etc("ztopbt.conf") {
  source = "cfg/ztopbt.conf"
  install_enable = true
  install_images = [ chipset_base_dir ]
  subsystem_name = "device_shaolingun"
  part_name = "device_shaolingun"
  relative_install_dir = "./bluetooth"
}

ohos_shared_library("libbt_vendor") {
  output_name = "libbt_vendor"

  sources = [
    "codec/plc/sbcplc.c",
    "codec/sbc/sbc.c",
    "codec/sbc/sbc_primitives.c",
    "codec/sbc/sbc_primitives_mmx.c",
    "codec/sbc/sbc_primitives_neon.c",
    "src/ztop_socket.c",
    "src/bt_vendor_ztop.c",
    "src/hardware.c",
    "src/userial_vendor.c",
    "src/upio.c",
    "src/bt_list.c",
    "src/bt_skbuff.c",
    "src/hci_h5.c",
    "src/ztop_parse.c",
    "src/ztop_btservice.c",
    "src/hardware_uart.c",
    "src/hardware_usb.c",
    "src/ztop_heartbeat.c",
    "src/ztop_poll.c",
    "src/ztop_btsnoop_net.c",
  ]

  include_dirs = [
    "include",
    "codec/sbc",
    "codec/plc",
    "//commonlibrary/c_utils/base/include",
    "//base/hiviewdfx/interfaces/innerkits/libhilog/include",
    "//drivers/peripheral/bluetooth/hci/hdi_service/implement",
  ]

  configs = [ ":bt_warnings" ]

  external_deps = [
    "c_utils:utils",
    "hilog:libhilog",
  ]

  install_enable = true
  install_images = [ chipset_base_dir ]

  subsystem_name = "device_shaolingun"
  part_name = "device_shaolingun"
}

配置完成后,编译系统会将:

ztop_bt_usb.ko
ztopbt.conf
libbt_vendor.z.so

打包到对应镜像中。


6.2 修改 bundle.json

为了让蓝牙适配部件参与系统编译,需要修改:

device/board/hisilicon/shaolingun/bundle.json

sub_component 中加入蓝牙构建目标:

{
  "build": {
    "sub_component": [
      "//device/board/hisilicon/shaolingun/cfg:init_configs",
      "//device/board/hisilicon/shaolingun/hardware:hardware_group",
      "//device/board/hisilicon/shaolingun/bluetooth:bt_group"
    ],
    "test": []
  }
}

完成后,执行项目对应的增量编译命令,即可将蓝牙 Vendor 适配层和相关配置文件集成到系统镜像中。


7. OpenHarmony 蓝牙接口适配

OpenHarmony 蓝牙框架通过 HDI Service 与底层 Vendor 适配库交互。对于具体蓝牙模组而言,接口适配的重点在于确保:

  • HDI Service 能够正确加载 libbt_vendor.z.so
  • Vendor 库提供的 initopclose 等接口符合 OpenHarmony 预期;
  • HCI 通路初始化成功;
  • 蓝牙控制命令和事件能够正常收发;
  • 蓝牙服务启动过程中无 HCI 初始化失败、权限不足或设备节点缺失等异常。

本案例中,兆通微厂商提供的源码原始目标环境为 Android,因此在 OpenHarmony 6.1 Release 中集成时,需要重点关注接口定义的差异。

参考文档:

芯片解决方案--SL8541e-OpenHarmony蓝牙适配分析及方案
兆通微 9612U 模组OpenHarmony蓝牙驱动接口适配方案


8. 适配验证建议

完成编译和烧录后,可以从以下几个方面验证适配结果。

8.1 驱动加载验证

确认内核模块是否已加载:

lsmod | grep ztop

查看内核日志:

dmesg | grep -i ztop
dmesg | grep -i bluetooth
dmesg | grep -i usb

如果 ztop_bt_usb.ko 加载失败,通常需要重点检查:

.ko 文件路径是否正确;

uname -r 是否与编译时 KVER 一致;

内核符号是否匹配;

init 阶段是否正确执行 insmod

USB 蓝牙设备是否被内核识别。


8.2 文件打包验证

确认相关文件是否已进入系统镜像:

ls -l /vendor/etc/bluetooth/

预期应能看到:

ztop_bt_usb.ko
ztopbt.conf

同时确认 Vendor 库是否存在:

ls -l /vendor/lib64/ | grep libbt_vendor

或根据实际安装路径检查:

find /vendor -name "libbt_vendor*"

8.3 蓝牙服务验证

查看蓝牙相关日志

hilog | grep -i bluetooth
hilog | grep -i hci
hilog | grep -i vendor

适配成功后,通常应满足以下现象:

  • 蓝牙服务正常启动;
  • HCI 初始化无失败日志;
  • 系统设置中可以打开蓝牙;
  • 可以扫描附近蓝牙设备;
  • 可完成基础配对或连接测试。

9. 总结

本案例完成了 mp_hi3781v735 平台上兆通微 9612U USB 蓝牙模组在 OpenHarmony 6.1 Release 中的适配工作。整体适配链路可以概括为:

USB 蓝牙硬件
    -> ztop_bt_usb.ko 内核驱动
        -> libbt_vendor.z.so Vendor 适配层
            -> OpenHarmony 蓝牙 HDI Service
                -> 蓝牙协议栈与应用层接口

其中:

  • ztop_bt_usb.ko 负责内核态 USB 蓝牙设备驱动;

  • libbt_vendor.z.so 负责用户态 HCI 传输和厂商适配;

  • ztopbt.conf 提供模组相关配置;

  • init 配置负责系统启动阶段自动加载驱动并设置设备权限;

  • BUILD.gnbundle.json 负责将相关产物纳入 OpenHarmony 编译和镜像打包流程。

从适配经验看,蓝牙模组迁移到 OpenHarmony 平台时,最关键的是理清 内核驱动、Vendor 适配层、HDI Service、系统权限和镜像打包 之间的关系。只要这几层边界清楚,后续定位编译失败、驱动加载失败或蓝牙服务初始化失败都会更有方向。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐