i.MX8QM BT 驱动移植

一、硬件信息
如下图 1 所示,使用的慧翰微模块 CBM252 BT 部分连接到了主控 i.MX8QM 端的 UART1 以及 SAI0 接口,UART 主要是负责控制命令以及媒体播放数据的传输,SA0 主要是负责通话部分的数据通信,我们这里主要介绍蓝牙连接以及媒体播放的部分。
 
图 1
 
二、驱动移植
 
① 首先,跟蓝牙厂商获取驱动移植代码或者移植库,我这里主要获取了两个文件:BTFW_CBM252.hcd 固件以及 libbluetooth.so 库文件。然后将 BTFW_CBM252.hcd 固件放到 android_build/out/target/product/mek_8q/vendor/firmware/brcm 下,将 libbluetooth.so 库文件放到 android_build/out/target/product/mek_8q/system/lib64 下。
 
② 关闭默认 libbluetooth.so 文件生成,system/bt/main/Android.bp 文件修改如下:
diff --git a/main/Android.bp b/main/Android.bp
index c07b849..531752e 100644
--- a/main/Android.bp
+++ b/main/Android.bp
@@ -1,7 +1,7 @@

// Bluetooth main HW module / shared library for target
// ========================================================
-cc_library_shared {
+/*cc_library_shared {
name: "libbluetooth",
defaults: ["fluoride_defaults"],
header_libs: ["libbluetooth_headers"],
@@ -85,7 +85,7 @@ cc_library_shared {
cflags: [
"-DBUILDCFG",
],
-}
+}*/
③ 蓝牙配置文件修改:
device/fsl/imx8q/mek_8q/mek_8q.mk
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.audio.output.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.audio.output.xml \
+ frameworks/native/data/etc/android.hardware.bluetooth.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.bluetooth.xml \
frameworks/native/data/etc/android.hardware.bluetooth_le.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.bluetooth_le.xml \
frameworks/native/data/etc/android.hardware.opengles.aep.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.opengles.aep.xml \
frameworks/native/data/etc/android.hardware.screen.landscape.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.screen.landscape.xml \
@@ -222,6 +223,15 @@ PRODUCT_PACKAGES += \
android.hardware.bluetooth@1.0-impl \
android.hardware.bluetooth@1.0-service

+#PRODUCT_PACKAGES += \
+ libbt-vendor
+#PRODUCT_PACKAGES += \
+ bt_vendor.conf
+PRODUCT_COPY_FILES += \
+ vendor/nxp/imx-firmware/brcm/FLC_CBM252/BTFW_CBM252.hcd:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/BTFW_CBM252.hcd \
+ hardware/broadcom/libbt/conf/fsl/mek_8q/bt_vendor.conf:$(TARGET_COPY_OUT_VENDOR)/etc/bluetooth/bt_vendor.conf \
+ hardware/broadcom/libbt/conf/fsl/mek_8q/bt_vendor.conf:$(TARGET_COPY_OUT_VENDOR)/../etc/bluetooth/bt_vendor.conf
 
hardware/broadcom/libbt/conf/fsl/mek_8q/bt_vendor.conf
-FwPatchFilePath = /vendor/firmware/bcm/1FD_BCM89359/
+FwPatchFilePath = /vendor/firmware/brcm

-FwPatchFileName = Type_ZP.hcd
+#FwPatchFileName = Type_ZP.hcd
+FwPatchFileName = BTFW_CBM252.hcd
注:此处 bt_vendor.conf 文件的配置需要与固件名进行适配
 
hardware/broadcom/libbt/include/vnd_generic.txt
BLUETOOTH_UART_DEVICE_PORT = "/dev/ttyLP1"
VENDOR_LIB_CONF_FILE = "/vendor/etc/bluetooth/bt_vendor.conf"
VNDUSERIAL_DBG = TRUE
LPM_SLEEP_MODE = 0
UART_TARGET_BAUD_RATE = 3000000
 
hardware/broadcom/libbt/include/vnd_mek_8q.txt
-FW_PATCHFILE_LOCATION = "/vendor/firmware/bcm/1FD_BCM89359/Type_ZP.hcd"
+FW_PATCHFILE_LOCATION = "/vendor/firmware/brcm"
+VENDOR_LIB_CONF_FILE = "/vendor/etc/bluetooth/bt_vendor.conf"
 
device/fsl/imx8q/mek_8q/BoardConfig.mk
-BOARD_HAVE_BLUETOOTH_QCOM := true
-BOARD_HAS_QCA_BT_ROME := true
+BOARD_HAVE_BLUETOOTH_QCOM := false
+BOARD_HAS_QCA_BT_ROME := false
+BOARD_HAVE_BLUETOOTH := true
+BOARD_HAVE_BLUETOOTH_BCM := true
BOARD_HAVE_BLUETOOTH_BLUEZ := false
-QCOM_BT_USE_SIBS := true
+QCOM_BT_USE_SIBS := false
 
packages/apps/Bluetooth/res/values/config.xml
 
packages/apps/Bluetooth/src/com/android/bluetooth/a2dpsink/A2dpSinkStateMachine.java
 public class A2dpSinkStateMachine extends StateMachine {
- private static final boolean DBG = false;
+ //zhengxiong
+ private static final boolean DBG = true;
 
packages/apps/Bluetooth/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
public class A2dpSinkStreamHandler extends Handler {
- private static final boolean DBG = false;
+ //zhengxiong
+ private static final boolean DBG = true;
private static final String TAG = "A2dpSinkStreamHandler";

// Configuration Variables
@@ -371,11 +372,15 @@ public class A2dpSinkStreamHandler extends Handler {
}

private boolean isIotDevice() {
- return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_EMBEDDED);
+ //zhengxiong
+ //return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_EMBEDDED);
+ return true;
}

private boolean isTvDevice() {
- return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ //zhengxiong
+ //return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ return true;
}
 
packages/apps/Bluetooth/src/com/android/bluetooth/a2dpsink/mbs/A2dpMediaBrowserService.java
 public class A2dpMediaBrowserService extends MediaBrowserService {
private static final String TAG = "A2dpMediaBrowserService";
- private static final boolean DBG = false;
- private static final boolean VDBG = false;
+ //zhengxiong
+ private static final boolean DBG = true;
+ private static final boolean VDBG = true;
 
packages/apps/Bluetooth/src/com/android/bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
 public class AvrcpControllerService extends ProfileService {
static final String TAG = "AvrcpControllerService";
- static final boolean DBG = false;
- static final boolean VDBG = false;
+ //zhengxiong
+ static final boolean DBG = true;
+ static final boolean VDBG = true;
 
packages/apps/Bluetooth/src/com/android/bluetooth/hfpclient/connserv/HfpClientDeviceBlock.java
-                mTelecomManager.addNewUnknownCall(mPhoneAccount.getAccountHandle(), b);
+ //zhengxiong
+ //mTelecomManager.addNewUnknownCall(mPhoneAccount.getAccountHandle(), b);
 
④ 修改内核编译配置文件文件 , 修改的路径为 :
vendor/nxp-opensource/kernel_imx/arch/arm64/configs/android_defconfig
CONFIG_USB_SERIAL=y
CONFIG_USB_SERIAL_CONSOLE=y
CONFIG_USB_SERIAL_GENERIC=y
CONFIG_USB_SERIAL_SIMPLE=y
CONFIG_USB_SERIAL_CH341=m
CONFIG_USB_SERIAL_FTDI_SIO=y
CONFIG_WLAN_VENDOR_BROADCOM=y
CONFIG_BCMDHD=m
CONFIG_BCM4373=y
CONFIG_BCMDHD_SDMMC=y
CONFIG_BCMDHD_SDIO=y
CONFIG_BCMDHD_VENDOR_EXT=y
CONFIG_BCMDHD_WPA3=y
 
⑤ 增加 USB 驱动接口权限,主要是以修改 *.te 配置文件,修改详情如下:
device/fsl/imx8q/mek_8q/sepolicy/file_contexts
/dev/ttyUSB[0-1]*               u:object_r:ttyUSB0_device:s0
/dev/ttyLP[0-1]* u:object_r:ttyLP1_device:s0
 
device/fsl/imx8q/sepolicy/file_contexts
/dev/ttyUSB0                    u:object_r:ttyUSB0_device:s0
/dev/ttyLP1 u:object_r:ttyLP1_device:s0
 
device/fsl/imx8q/sepolicy/device.te
type ttyUSB0_device, dev_type;
type ttyLP1_device, dev_type;​

device/fsl/imx8q/sepolicy/hal_bluetooth_default.te
allow hal_bluetooth_default ttyUSB0_device:chr_file { open read write ioctl};
allow hal_bluetooth_default ttyLP1_device:chr_file { open read write ioctl};
 
device/fsl/imx8q/sepolicy/hal_health_default.te
allow hal_health_default sysfs:file read;
allow hal_health_default sysfs:file {open write read};
 
⑥ 修改 dts 及驱动文件:
vendor/nxp-opensource/kernel_imx/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek.dtsi
SC_P_FLEXCAN2_TX_LSIO_GPIO4_IO02                0x00000021
SC_P_FLEXCAN2_RX_LSIO_GPIO4_IO01 0x00000021
 
vendor/nxp-opensource/kernel_imx/drivers/bluetooth/mx8_bt_rfkill.c
int ret;

printk("[pual] Enable BT_HOST_WAKE %s - %d -- \n",__func__,__LINE__);
ret = gpio_request(353, "BT_HOST_WAKE");//第一个参数,为要申请的引脚,第二个为你要定义的名字
if (ret)
{
printk("[pual] gpio_request error %s - %d -- \n",__func__,__LINE__);
return ret;
}
gpio_direction_output(353, 0);
gpio_set_value(353, 1);

msleep(100);

printk("[pual] Enable BT_WAKE %s - %d -- \n",__func__,__LINE__);
ret = gpio_request(354, "BT_WAKE");//第一个参数,为要申请的引脚,第二个为你要定义的名字
if (ret)
{
printk("[pual] gpio_request error %s - %d -- \n",__func__,__LINE__);
return ret;
}
gpio_direction_output(354, 0);
gpio_set_value(354, 1);

msleep(100);
 
完成以上 BT 代码移植后,开始编译,烧录镜像。
 
三、功能验证
 
启动设备,打开蓝牙可以看到,默认设备名称为 iMX8。通过手机连接 iMX8 设备,可以看到如下设备端和手机端匹配的画面,最后连接成功。
 
 
 
 
 
注:启动后查看 logcat 有如下报错:
JNI DETECTED ERROR IN APPLICATION: can't call void com.android.bluetooth.hfpclient.NativeInterface.onConnectionStateChanged
 
解决方法:
packages/apps/Bluetooth/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
diff --git a/src/com/android/bluetooth/hfpclient/HeadsetClientService.java b/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
index e978a03..55bde40 100644
--- a/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
+++ b/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
@@ -64,10 +64,6 @@

public static final String HFP_CLIENT_STOP_TAG = "hfp_client_stop_tag";

- static {
- NativeInterface.classInitNative();
- }
-
@Override
public IProfileServiceBinder initBinder() {
return new BluetoothHeadsetClientBinder(this);
@@ -78,8 +74,15 @@
if (DBG) {
Log.d(TAG, "start()");
}
+ if (sHeadsetClientService != null) {
+ Log.w(TAG, "start(): start called without stop");
+ return false;
+ }
+
// Setup the JNI service
- NativeInterface.initializeNative();
+ mNativeInterface = new NativeInterface();
+ mNativeInterface.initializeNative();
+
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

mSmFactory = new HeadsetClientStateMachineFactory();
@@ -88,8 +91,6 @@
IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
registerReceiver(mBroadcastReceiver, filter);

- mNativeInterface = new NativeInterface();
-
// Start the HfpClientConnectionService to create connection with telecom when HFP
// connection is available.
Intent startIntent = new Intent(this, HfpClientConnectionService.class);
@@ -125,13 +126,13 @@
Intent stopIntent = new Intent(this, HfpClientConnectionService.class);
stopIntent.putExtra(HFP_CLIENT_STOP_TAG, true);
startService(stopIntent);
- mNativeInterface = null;

// Stop the handler thread
mSmThread.quit();
mSmThread = null;

- NativeInterface.cleanupNative();
+ mNativeInterface.cleanupNative();
+ mNativeInterface = null;

return true;
}
 
packages/apps/Bluetooth/src/com/android/bluetooth/hfpclient/NativeInterface.java
diff --git a/src/com/android/bluetooth/hfpclient/NativeInterface.java b/src/com/android/bluetooth/hfpclient/NativeInterface.java
index 77d9af7..0a6b9c6 100644
--- a/src/com/android/bluetooth/hfpclient/NativeInterface.java
+++ b/src/com/android/bluetooth/hfpclient/NativeInterface.java
@@ -28,14 +28,18 @@
private static final String TAG = "NativeInterface";
private static final boolean DBG = false;

+ static {
+ classInitNative();
+ }
+
NativeInterface() {}

// Native methods that call into the JNI interface
static native void classInitNative();

- static native void initializeNative();
+ native void initializeNative();

- static native void cleanupNative();
+ native void cleanupNative();

static native boolean connectNative(byte[] address);
 
以上便完成了,i.MX8QM BT 驱动功能的移植。

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论