#!/usr/bin/env bash # SPDX-License-Identifier: (GPL-2.0-only OR MIT) # Copyright (C) 2026 Amlogic, Inc. All rights reserved ################################################################################ # Amlbian Bluetooth W2L Driver Compilation Package # # Purpose: Build W2L bluetooth kernel module with Hook support and aml-comp integration # Provides: Bluetooth driver kernel module, firmware installation # Based on Yocto recipe: aml-bt-w2l_1.0.bb ################################################################################ set -e # Get script directory SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" AMLBIAN_DIR="$(dirname "$(dirname "${SCRIPT_DIR}")")" BASE_DIR="$(dirname "$(dirname "${AMLBIAN_DIR}")")" # Source common functions if [[ -f "${AMLBIAN_DIR}/lib/function-common.sh" ]]; then source "${AMLBIAN_DIR}/lib/function-common.sh" fi # Source ADLA build script if it exists HCIATTACH_SCRIPT="${SCRIPT_DIR}/build-hciattach.sh" if [[ -f "${HCIATTACH_SCRIPT}" ]]; then display_alert "Loading hciattach build script" "${HCIATTACH_SCRIPT}" "info" source "${HCIATTACH_SCRIPT}" else display_alert "hciattach build script not found" "${HCIATTACH_SCRIPT}" "warn" fi # ============================================================================== # Shared Helper Functions # ============================================================================== # ------------------------------------------------------------------------------ # Step 1: Package Information Definition # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Step 2: Build Directory Structure Setup # ------------------------------------------------------------------------------ # Create layered build directory structure # Parameters: # $1 - base name (e.g. "${PKG_NAME}_${PKG_VERSION}_${PKG_ARCH}") # Sets: TMP_DIR, BASE_BUILD_DIR, SOURCE_DIR, BUILD_DIR, INSTALL_DIR, PATCH_DIR, # DEB_PACKAGE_DIR, DEBIAN_DIR, MODULE_DIR, FIRMWARE_DIR, BUILD_LOG function _bt_common_create_build_dirs() { local base_name="$1" TMP_DIR="${SRC}/.tmp" mkdir -p "${TMP_DIR}" # 基础构建目录 BASE_BUILD_DIR="${TMP_DIR}/${base_name}" rm -rf ${BASE_BUILD_DIR} # 分层目录 SOURCE_DIR="${BASE_BUILD_DIR}/source" # 源码目录 BUILD_DIR="${BASE_BUILD_DIR}/build" # 编译目录 INSTALL_DIR="${BASE_BUILD_DIR}/install" # 安装目录 PATCH_DIR="${BASE_BUILD_DIR}/patch" # 补丁目录 # 创建所有目录 mkdir -p "${SOURCE_DIR}" mkdir -p "${BUILD_DIR}" mkdir -p "${INSTALL_DIR}" mkdir -p "${PATCH_DIR}" # 在BUILD_DIR下创建deb/包名目录 DEB_PACKAGE_DIR="${BUILD_DIR}/deb/${base_name}" mkdir -p "${DEB_PACKAGE_DIR}" # 创建编译日志文件 BUILD_LOG="${BUILD_DIR}/build.log" # 获取内核版本 local KERNEL_VERSION=$(make -s -C "${KERNEL_BUILD_DIR}" kernelrelease 2>/dev/null || echo "unknown-$(date +%Y%m%d)") # 安装目录的子目录 DEBIAN_DIR="${INSTALL_DIR}/DEBIAN" MODULE_DIR="${INSTALL_DIR}/lib/modules/${KERNEL_VERSION}/kernel/drivers/amlogic/bt" FIRMWARE_DIR="${INSTALL_DIR}/lib/firmware/aml" mkdir -p "${DEBIAN_DIR}" mkdir -p "${MODULE_DIR}" mkdir -p "${FIRMWARE_DIR}" } # Display build directory info # Parameters: # $1 - log prefix function _bt_common_display_build_info() { local log_prefix="$1" local KERNEL_VERSION=$(make -s -C "${KERNEL_BUILD_DIR}" kernelrelease 2>/dev/null || echo "unknown-$(date +%Y%m%d)") display_alert "${log_prefix} Source dir: ${SOURCE_DIR}" "info" display_alert "${log_prefix} Build dir: ${BUILD_DIR}" "info" display_alert "${log_prefix} Install dir: ${INSTALL_DIR}" "info" display_alert "${log_prefix} Patch dir: ${PATCH_DIR}" "info" display_alert "${log_prefix} Deb package dir: ${DEB_PACKAGE_DIR}" "info" display_alert "${log_prefix} Build log: ${BUILD_LOG}" "info" display_alert "${log_prefix} Module dir: ${MODULE_DIR}" "info" display_alert "${log_prefix} Firmware dir: ${FIRMWARE_DIR}" "info" display_alert "${log_prefix} Kernel version: ${KERNEL_VERSION}" "info" } # ------------------------------------------------------------------------------ # Step 3: Source File Validation and Copying # ------------------------------------------------------------------------------ # Validate and copy source files # Parameters: # $1 - source directory path # $2 - component name (for logging) function _bt_common_validate_and_copy_sources() { local src_dir="$1" local component="$2" # Check if source directory exists if [[ ! -d "${src_dir}" ]]; then display_alert "COMPILE-${component} Bluetooth driver source code not found" "${src_dir}" "error" exit 1 fi # Copy source to source directory display_alert "COMPILE-${component} Copying source files to source directory" "info" echo "Copying source files to source directory at $(date)" > "${BUILD_LOG}" cp -r "${src_dir}/"* "${SOURCE_DIR}/" 2>&1 >> "${BUILD_LOG}" } # ------------------------------------------------------------------------------ # Step 8: Debian Package Building # ------------------------------------------------------------------------------ # Build Debian package from install directory # Parameters: # $1 - log prefix (e.g. "COMPILE-BT-W2L") # $2 - output deb filename (without path) # Sets: OUTPUT_DEB function _bt_common_build_deb_package() { local log_prefix="$1" local output_deb_name="$2" local KERNEL_VERSION=$(make -s -C "${KERNEL_BUILD_DIR}" kernelrelease 2>/dev/null || echo "unknown-$(date +%Y%m%d)") # 将install目录内容拷贝到deb目录 display_alert "${log_prefix} Copying install directory to deb package directory" "info" echo "Copying install directory to deb package directory at $(date)" >> "${BUILD_LOG}" cp -r "${INSTALL_DIR}/"* "${DEB_PACKAGE_DIR}/" 2>&1 >> "${BUILD_LOG}" # 基于deb目录打包 display_alert "${log_prefix} Building Debian package" "info" echo "Building Debian package at $(date)" >> "${BUILD_LOG}" dpkg-deb --build "${DEB_PACKAGE_DIR}" 2>&1 >> "${BUILD_LOG}" if [[ $? -ne 0 ]]; then display_alert "${log_prefix} Package build failed" "error" exit 1 fi # Move to output directory OUTPUT_DEB="${SRC}/output/${output_deb_name}" mkdir -p "$(dirname "${OUTPUT_DEB}")" mv "${DEB_PACKAGE_DIR}.deb" "${OUTPUT_DEB}" display_alert "${log_prefix} Package built successfully ${output_deb_name}" "info" display_alert "${log_prefix} Build directory preserved ${BASE_BUILD_DIR}" "info" } # ============================================================================== # Generic Bluetooth Driver Build Functions # ============================================================================== # Initialize package metadata for Bluetooth driver # Parameters: # $1 - driver type (w2l or w2) function _bt_init_package_info() { local driver_type="$1" PKG_MAINTAINER="Armbian Build " PKG_DESCRIPTION="Amlogic ${driver_type^^} bluetooth driver" PKG_NAME="aml-bt-${driver_type}" PKG_VERSION="1.0" PKG_ARCH="${ARCH:-arm64}" COMPONENT="bt-${driver_type}" # Cross compilation settings CROSS_COMPILE="${CROSS_COMPILE:-aarch64-linux-gnu-}" # Driver configuration DRIVER_NAME="${driver_type}_bt" DRIVER_MODULE="${DRIVER_NAME}.ko" # Source directory for bluetooth driver BT_SRC_DIR="${BASE_DIR}/aml-comp/hardware/bluetooth/amlogic/${driver_type}" # Firmware source directory BT_FIRMWARE_DIR="${BASE_DIR}/aml-comp/hardware/bluetooth/amlogic/${driver_type}" # Kernel directories KERNEL_BUILD_DIR="${BASE_DIR}/aml-comp/kernel/aml-6.12/build" STAGING_KERNEL_DIR="${BASE_DIR}/aml-comp/kernel/aml-6.12" } # Validate kernel build environment # Parameters: # $1 - driver type (w2l or w2) # $2 - temporary directory path function _bt_validate_kernel_env() { local driver_type="$1" local tmp_dir="$2" # Check for kernel headers if [[ ! -d "${KERNEL_BUILD_DIR}" ]]; then display_alert "COMPILE-${COMPONENT} Kernel build directory not found" "${KERNEL_BUILD_DIR}" "error" exit 1 fi # Get wifi driver Module.symvers path local WIFI_MODULE_SYMS="${tmp_dir}/aml-wifi-${driver_type}_1.0_${PKG_ARCH}/source/aml_drv/Module.symvers" # Check if wifi driver Module.symvers exists if [[ ! -f "${WIFI_MODULE_SYMS}" ]]; then display_alert "COMPILE-${COMPONENT} Wifi driver Module.symvers not found" "${WIFI_MODULE_SYMS}" "warn" display_alert "COMPILE-${COMPONENT} Building wifi driver first..." "info" if [[ ! -f "${WIFI_MODULE_SYMS}" ]]; then display_alert "COMPILE-${COMPONENT} Failed to build wifi driver or Module.symvers not found" "error" exit 1 fi fi display_alert "COMPILE-${COMPONENT} Using wifi Module.symvers" "${WIFI_MODULE_SYMS}" "info" # Return the path to wifi Module.symvers echo "${WIFI_MODULE_SYMS}" } # Build bluetooth kernel module # Parameters: # $1 - source directory path # $2 - path to wifi driver Module.symvers function _bt_build_module() { local src_dir="$1" local wifi_module_syms="$2" display_alert "COMPILE-${COMPONENT} Building ${DRIVER_NAME} kernel module" "info" # Change to source directory cd "${src_dir}" # Based on Yocto recipe: EXTRA_OEMAKE='-C ${S}/aml_bt/${driver_type} M=${S}/aml_bt/${driver_type} KERNEL_SRC=${STAGING_KERNEL_DIR} ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE}' make -C "${KERNEL_BUILD_DIR}" \ M="${src_dir}" \ KBUILD_EXTRA_SYMBOLS="${wifi_module_syms}" \ KERNEL_SRC="${STAGING_KERNEL_DIR}" \ ARCH="${PKG_ARCH}" \ CROSS_COMPILE="${CROSS_COMPILE}" \ modules # Check if module was built if [[ ! -f "${src_dir}/${DRIVER_MODULE}" ]]; then display_alert "COMPILE-${COMPONENT} Module build failed. Could not find ${DRIVER_MODULE}" "error" exit 1 fi display_alert "COMPILE-${COMPONENT} Module built successfully: ${DRIVER_MODULE}" "info" # 在BUILD_DIR中保存编译结果(备份) display_alert "COMPILE-${COMPONENT} Saving build result to build directory" "info" mkdir -p "${BUILD_DIR}/modules" cp -f "${src_dir}/${DRIVER_MODULE}" "${BUILD_DIR}/modules/" } # Install module and firmware files # Parameters: # $1 - source directory path # $2 - driver type (w2l or w2) function _bt_install_files() { local src_dir="$1" local driver_type="$2" # Install module to INSTALL_DIR(用于打包) display_alert "COMPILE-${COMPONENT} Installing module to install directory ${MODULE_DIR}" "info" install -m 0666 "${src_dir}/${DRIVER_MODULE}" "${MODULE_DIR}/" # Install firmware files to INSTALL_DIR # Firmware source: ${S}/aml_bt/firmware/${driver_type}_bt_15p4_fw_*.bin display_alert "COMPILE-${COMPONENT} Installing firmware files to install directory ${FIRMWARE_DIR}" "info" if [[ -d "${BT_FIRMWARE_DIR}" ]]; then if [[ "${driver_type}" == "w2l" ]]; then install -m 0666 ${BT_FIRMWARE_DIR}/${driver_type}_bt_15p4_fw_*.bin "${FIRMWARE_DIR}/" 2>/dev/null || true else install -m 0666 ${BT_FIRMWARE_DIR}/${driver_type}_bt_*fw*.bin "${FIRMWARE_DIR}/" 2>/dev/null || true fi fi } # Create Debian control file # Parameters: # $1 - driver type (w2l or w2) function _bt_create_control_file() { local driver_type="$1" local KERNEL_VERSION=$(make -s -C "${KERNEL_BUILD_DIR}" kernelrelease 2>/dev/null || echo "unknown-$(date +%Y%m%d)") display_alert "COMPILE-${COMPONENT} Creating control file DEBIAN/control" "info" cat > "${DEBIAN_DIR}/control" << EOF Package: ${PKG_NAME} Version: ${PKG_VERSION} Architecture: ${PKG_ARCH} Maintainer: ${PKG_MAINTAINER} Depends: aml-wifi-${driver_type} Section: kernel Priority: optional Description: ${PKG_DESCRIPTION} This package provides the kernel module for Amlogic ${driver_type^^} bluetooth. It includes the ${DRIVER_NAME} module for bluetooth functionality. EOF } # Create post-installation script # Parameters: # $1 - driver type (w2l or w2) function _bt_create_postinst() { local driver_type="$1" local KERNEL_VERSION="$2" display_alert "COMPILE-${COMPONENT} Creating post-installation script: DEBIAN/postinst" "info" cat > "${DEBIAN_DIR}/postinst" << EOF #!/bin/bash set -e if [ "\$1" = "configure" ]; then # run depmod only if /lib/modules/${KERNEL_VERSION} exists if [ -d "/lib/modules/${KERNEL_VERSION}" ]; then depmod -a "${KERNEL_VERSION}" else echo "Warning: /lib/modules/${KERNEL_VERSION} not found, skipping depmod" fi # try to load module but don't error if modprobe -n ${driver_type}_bt 2>/dev/null; then echo "Amlogic ${driver_type^^} bluetooth module can be loaded with 'modprobe ${driver_type}_bt'" fi fi exit 0 EOF chmod 755 "${DEBIAN_DIR}/postinst" } # Create pre-removal script # Parameters: # $1 - driver type (w2l or w2) function _bt_create_prerm() { local driver_type="$1" display_alert "COMPILE-${COMPONENT} Creating pre-removal script: DEBIAN/prerm" "info" cat > "${DEBIAN_DIR}/prerm" << EOF #!/bin/bash set -e if [ "\$1" = "remove" ] || [ "\$1" = "deconfigure" ]; then # Unload module if loaded if lsmod | grep -q "${driver_type}_bt"; then modprobe -r ${driver_type}_bt 2>/dev/null || true fi fi exit 0 EOF chmod 755 "${DEBIAN_DIR}/prerm" } # Generic Bluetooth driver package build function # Parameters: # $1 - driver type (w2l or w2) function amlbian_build_bt_driver() { local driver_type="$1" set -e # ---- Step 1: Version and Package Information ---- _bt_init_package_info "${driver_type}" local KERNEL_VERSION=$(make -s -C "${KERNEL_BUILD_DIR}" kernelrelease 2>/dev/null || echo "unknown-$(date +%Y%m%d)") display_alert "COMPILE-${COMPONENT} Building ${driver_type^^} bluetooth driver version ${PKG_VERSION} for ${PKG_ARCH}" "info" display_alert "COMPILE-${COMPONENT} Building ${driver_type^^} bluetooth driver for kernel ${KERNEL_VERSION}" "info" # ---- Step 2: Build Directory Setup ---- _bt_common_create_build_dirs "${PKG_NAME}_${PKG_VERSION}_${PKG_ARCH}" _bt_common_display_build_info "COMPILE-${COMPONENT}" # ---- Step 3: Source File Validation and Copying ---- _bt_common_validate_and_copy_sources "${BT_SRC_DIR}" "${COMPONENT}" # Update source directory to the copied location local SRC_DIR_COPY="${SOURCE_DIR}" # ---- Step 4: Kernel Build Environment Validation ---- local wifi_module_syms=$(_bt_validate_kernel_env "${driver_type}" "${TMP_DIR}") # ---- Step 5: Build Bluetooth Kernel Module ---- _bt_build_module "${SRC_DIR_COPY}" "${wifi_module_syms}" # ---- Step 6: File Installation ---- _bt_install_files "${SRC_DIR_COPY}" "${driver_type}" # ---- Step 7: Debian Packaging Scripts ---- _bt_create_control_file "${driver_type}" _bt_create_postinst "${driver_type}" "${KERNEL_VERSION}" _bt_create_prerm "${driver_type}" # ---- Step 8: Build Debian Package ---- _bt_common_build_deb_package "COMPILE-${COMPONENT}" "${PKG_NAME}_${PKG_VERSION}_${KERNEL_VERSION}_${PKG_ARCH}.deb" display_alert "COMPILE-${COMPONENT} ${driver_type^^} bluetooth driver package build completed" "success" display_alert "COMPILE-${COMPONENT} Build directories preserved:" "info" display_alert "COMPILE-${COMPONENT} Source: ${SOURCE_DIR}" "info" display_alert "COMPILE-${COMPONENT} Build: ${BUILD_DIR}" "info" display_alert "COMPILE-${COMPONENT} Install: ${INSTALL_DIR}" "info" display_alert "COMPILE-${COMPONENT} Patch: ${PATCH_DIR}" "info" display_alert "COMPILE-${COMPONENT} Deb package: ${DEB_PACKAGE_DIR}" "info" return 0 } # ------------------------------------------------------------------------------ # Main Bluetooth Build Function # ------------------------------------------------------------------------------ function amlbian_build_bt() { if ! is_unit_enabled "bt"; then echo "[SKIP] >> Bluetooth disable in BUILD_UNITS" return fi # Build W2 Bluetooth driver if [ "${BT_MODE:-}" = "w2" ]; then display_alert "Building W2 Bluetooth driver" "W2 enabled in BUILD_UNITS" "info" amlbian_build_bt_driver "w2" else display_alert "Skipping W2 Bluetooth driver" "W2 disabled in BUILD_UNITS" "info" fi # Build W2L Bluetooth driver if [ "${BT_MODE:-}" = "w2l" ]; then display_alert "Building W2L Bluetooth driver" "W2L enabled in BUILD_UNITS" "info" amlbian_build_bt_driver "w2l" else display_alert "Skipping W2L Bluetooth driver" "W2L disabled in BUILD_UNITS" "info" fi # Build HCI Attach tool if [ "${BT_HCIATTACH:-}" = "yes" ]; then display_alert "Building HCI Attach tool" "info" amlbian_build_hciattach else display_alert "Skipping HCI Attach tool" "info" fi } # ============================================================================== # Main Execution # ============================================================================== display_alert "AMLbian Bt Build Script BT_MODE $BT_MODE BT_HCIATTACH $BT_HCIATTACH BT_BLUEZ $BT_BLUEZ" "Starting Bt build" "info" amlbian_build_bt display_alert "AMLOGIC: Bt build completed" "Check output directory for packages" "info"