RPI: Raspberry Pi Zero W上的蓝牙 – 设备初始化的方式

找了之前写的关于Raspberry Pi上的蓝牙设备的相关配置,发现还在存在一些问题。

 

下面这篇是通过上层命令去初始化蓝牙设备:

Brillo: brillo-m10-dev @ RPi 3B – Bluetooth模块

下面再看看另外一种方式,由linux kernel去初始化蓝牙设备的方法

  • Linux Kernel

代码http://mirrors.ustc.edu.cn/aosp/kernel/common.git/

这里使用的是 android kernel中的android-4.19-q的代码,commit id:

commit ba835f8db4a3005e34542a3af7f19fce30ade6fd
Author: Jeff Vander Stoep <jeffv@google.com>
Date:   Wed Jan 22 11:19:58 2020 +0100

    ANDROID: selinux: modify RTM_GETLINK permission
    
  • device tree的配置

arch/arm/boot/dts/bcm2835-rpi-zero-w.dts中可以看到,在uart0上已经加了蓝牙相关的描述:

&uart0 {
    pinctrl-names = "default";
    pinctrl-0 = <&uart0_gpio32 &uart0_ctsrts_gpio30>;
    status = "okay";

    bluetooth {
        compatible = "brcm,bcm43438-bt";
        max-speed = <2000000>;
        shutdown-gpios = <&gpio 45 GPIO_ACTIVE_HIGH>;
    };
};
  • linux driver 层

由于上面device tree上描述,使用如果kernel编译时配置了CONFIG_BT_HCIUART_BCM=y时,就可以让drivers/bluetooth/hci_bcm.c去初始化蓝牙设备。

当然,在初始化蓝牙设备时,还需要相关的固件文件:BCM43430A1.hcd。

初始化时,我们可以从kernel log中看到如下信息:

[    4.289228] Bluetooth: hci0: command 0xfc18 tx timeout
[    4.383397] sdhost-bcm2835 20202000.mmc: loaded - DMA enabled (>1)
[    4.427188] mmc1: SDHCI controller on 20300000.mmcnr [20300000.mmcnr] using PIO
[    4.441914] hctosys: unable to open rtc device (rtc0)
[    4.452859] Bluetooth: hci0: BCM: chip id 94
[    4.462173] Bluetooth: hci0: BCM: features 0x2e
[    4.473474] Bluetooth: hci0: BCM43430A1
[    4.481723] Bluetooth: hci0: BCM43430A1 (001.002.009) build 0000
[    4.494815] cfg80211: Loading compiled-in X.509 certificates for regulatory database
    ...
[    5.798836] ueventd: ueventd started!
[    5.978242] Bluetooth: hci0: BCM43430A1 (001.002.009) build 0360
[    6.703432] ueventd: Coldboot took 0.89s.
[    6.712687] init: Waiting for /dev/.coldboot_done took 0.93s.

之后,我们就可以在系统中看到 /sys/class/rfkill/rfkill0 及/sys/devices/platform/soc/20201000.serial/serial0/serial0-0/bluetooth/hci0 这两个关于蓝牙设备的信息。

 

  • 上层应用

对于Brillo m10系统来说,与蓝牙设备进行交互的app为bluetoothtbd。这里,我们还需要一个libbt-vendor.so的动态库,实现与kernel driver层的交互。

由于driver已经初始化好蓝牙设备并且创建好了hci0的设备。我们的上层应用就可以通过hci0这个设备去与蓝牙设备进行交互。

这里会用到system/bt/vendor_libs/linux下的代码,commit id:

commit 10dd30d45a1f03bd7668df9e2cad4498d110ce0b
Author: Ajay Panicker <apanicke@google.com>
Date:   Thu Feb 18 16:33:07 2016 -0800

    Clean up dump printout
    
    Change-Id: I0b7e5a9dda30875c9fc877baffa0daac9184cd42

初始化代码:

static int bt_vendor_init(const bt_vendor_callbacks_t *p_cb,
                          unsigned char *local_bdaddr)
{
  char prop_value[PROPERTY_VALUE_MAX];

  LOG_INFO(LOG_TAG, "%s", __func__);

  if (p_cb == NULL) {
    LOG_ERROR(LOG_TAG, "init failed with no user callbacks!");
    return -1;
  }

  bt_vendor_callbacks = p_cb;

  memcpy(bt_vendor_local_bdaddr, local_bdaddr,
         sizeof(bt_vendor_local_bdaddr));

  property_get("bluetooth.interface", prop_value, "0");

  errno = 0;
  if (memcmp(prop_value, "hci", 3))
    hci_interface = strtol(prop_value, NULL, 10);
  else
    hci_interface = strtol(prop_value + 3, NULL, 10);
  if (errno)
    hci_interface = 0;

  LOG_INFO(LOG_TAG, "Using interface hci%d", hci_interface);

  property_get("bluetooth.rfkill", prop_value, "0");

  rfkill_en = atoi(prop_value);
  if (rfkill_en)
    LOG_INFO(LOG_TAG, "RFKILL enabled");

  bt_hwcfg_en = property_get("bluetooth.hwcfg",
                             prop_value, NULL) > 0 ? 1 : 0;
  if (bt_hwcfg_en)
    LOG_INFO(LOG_TAG, "HWCFG enabled");

  return 0;
}

配置三个系统属性:

– bluetooth.interface=hci0

– bluetooth.rfkill=0

– bluetooth.hwcfg=0

 

同时,从bluetoothtbd.rc文件中可以看到,该进程是以bluetooth的用户运行的,还需要具备CAP_NET_ADMIN 权限。

service bluetoothtbd /system/bin/bluetoothtbd
    class main
    user bluetooth
    group wakelock net_bt_admin net_bt_stack net_admin

这个权限可以在bluetoothtbd.rc中文件配置,也可以在fs_config/android_filesystem_config.h中配置:

/* Rules for files.
** These rules are applied based on "first match", so they
** should start with the most specific path and work their
** way up to the root. Prefixes ending in * denote wildcards
** and will allow partial matches.
*/
static const struct fs_path_config android_device_files[] = {
    { 00755, AID_SYSTEM,  AID_SHELL, CAP_MASK_LONG(CAP_NET_BIND_SERVICE) | CAP_MASK_LONG(CAP_NET_ADMIN) |
                                     CAP_MASK_LONG(CAP_NET_RAW),          "system/bin/dnsmasq" },

    { 00700, AID_SYSTEM,  AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND),    "system/bin/nativepowerman" },
    { 00700, AID_SYSTEM,  AID_SHELL, CAP_MASK_LONG(CAP_SYS_TIME),         "system/bin/tlsdated" },
    { 00700, AID_WEBSERV, AID_SHELL, CAP_MASK_LONG(CAP_NET_BIND_SERVICE), "system/bin/webservd" },
    { 00700, AID_DHCP,    AID_DBUS,  CAP_MASK_LONG(CAP_NET_ADMIN) |
                                     CAP_MASK_LONG(CAP_NET_BIND_SERVICE) |
                                     CAP_MASK_LONG(CAP_NET_RAW),          "system/bin/dhcpcd-6.8.2" },
    { 00700, AID_WIFI,    AID_SHELL, CAP_MASK_LONG(CAP_NET_ADMIN) |
                                     CAP_MASK_LONG(CAP_NET_RAW),          "system/bin/wpa_supplicant" },
    { 00755, AID_WIFI,    AID_SHELL, CAP_MASK_LONG(CAP_NET_ADMIN) |
                                     CAP_MASK_LONG(CAP_NET_RAW),          "system/bin/apmanager" },
    { 00755, AID_WIFI,    AID_SHELL, CAP_MASK_LONG(CAP_NET_ADMIN) |
                                     CAP_MASK_LONG(CAP_NET_RAW),          "system/bin/hostapd" },
    { 00700, AID_BLUETOOTH, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND) | CAP_MASK_LONG(CAP_WAKE_ALARM) |
                                     CAP_MASK_LONG(CAP_NET_ADMIN),        "system/bin/bluetoothtbd" },

    { 00550, AID_ROOT,    AID_SHELL, 0,                                    "system/etc/init.firewall-adbd-setup.sh" },
    { 00550, AID_ROOT,    AID_SHELL, 0,                                    "system/etc/init.firewall-setup.sh" },
    { 00550, AID_ROOT,    AID_SHELL, 0,                                    "system/etc/init.wifi-setup.sh" },

    { 00755, AID_SYSTEM,  AID_SHELL, CAP_MASK_LONG(CAP_NET_ADMIN) |
                                     CAP_MASK_LONG(CAP_NET_RAW),          "system/bin/iptables" },
    { 00755, AID_SYSTEM,  AID_SHELL, CAP_MASK_LONG(CAP_NET_ADMIN) |
                                     CAP_MASK_LONG(CAP_NET_RAW),          "system/bin/ip6tables" },

    { 00755, AID_SYSTEM,  AID_SHELL, CAP_MASK_LONG(CAP_NET_ADMIN) |
                                     CAP_MASK_LONG(CAP_NET_RAW),          "system/bin/crda" },

 

如果不去设置文件的capability, 在使用蓝牙设备时,会报如下错误:

01-24 11:00:11.887   123   220 I bt_vendor: bt_vendor_op op 3 retval 1
01-24 11:00:11.903   123   220 I bt_vendor: bt_vendor_op op 1
01-24 11:00:11.903   123   220 I bt_vendor: bt_vendor_fw_cfg
01-24 11:00:11.903   123   220 I bt_vendor: bt_vendor_wait_hcidev
01-24 11:00:11.904   123   220 E bt_vendor: socket bind error Operation not permitted
01-24 11:00:11.904   123   220 E bt_vendor: Hardware Config Error
01-24 11:00:11.904   123   220 I bt_vendor: firmware callback

初始化时,还需要蓝牙协议栈配置信息(配置log)文件:/etc/bluetooth/bt_stack.conf

01-24 11:00:19.963   123   178 E bt_hci  : command_timed_out restarting the bluetooth process.
01-24 11:00:20.003   113   113 I ServiceManager: service 'bluetooth-service' died
01-24 11:00:20.572   227   227 I bt_btif : init
01-24 11:00:20.581   227   228 I bt_stack_config: init attempt to load stack conf from /etc/bluetooth/bt_stack.conf
01-24 11:00:20.586   227   227 I bt_osi_wakelock: wakelock_set_os_callouts set to non-native

selinux权限

allow bluetoothtbd self:socket create_socket_perms;

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注