Android 10 Software Integration Guide for the LWB family radios

Overview

This document explains the steps required to integrate an LWB/LWB5/LWB5+ module into a device running Android 10.

Integrating Wi-Fi and Bluetooth into specific Android platforms can be challenging and may require platform specific changes. If the following information is confusing or does not provide the expected results, please visit https://www.ezurio.com/resources/support for further assistance.

Ezurio has integrated this radio with an available commercial development kit. Each required change to the AOSP will be shown here. Your system may be different and so these modifications may need further adjustments on your system.

Be sure to review the standard Software Integration Guide for the LWB family: sig_LWB_series_radio.pdf

Preliminary expectations

Familiarity with Android Open Source Project (AOSP)

We recommend you have built your development system initially prior to adding support from this document.

Required Packages

  • Backports package
  • Sterling Firmware package for the radio you are using

https://github.com/LairdCP/Sterling-LWB-and-LWB5-Release-Packages

Placement of code and firmware in AOSP

Create a directory “laird” as a child of your AOSP’s root directory and place the backports and appropriate firmware packages for the wifi/bt interface combination there. Use tar to expand each package in that directory. For backports, create a symlink named backport which points to the newly expanded backports directory. Examples:

(after sourcing your build/envsetup file)

$ croot
$ mkdir laird
$ cp <your download location>/laird-lwb*-firmware-*.tar.bz2 .
$ cp <your download location>/backports-laird-*.tar.bz2 .
$ tar xf laird-lwb*-firmware-*.tar.bz2
$ tar xf backports-laird-*.tar.bz2
$ ln -sf laird-backport-x.x.x.x/ backport

Compiling Backports

The backports driver package must be configured for the desired radio and then compiled against the proper Android Linux kernel for your project using the same compiler used for the remainder of the AOSP. The simplest way to accomplish this is to have the Android make system do the compilation. For our AOSP, we edited kernel.mk in the ./device/<company name>/common/build directory

diff --git a/common/build/kernel.mk b/common/build/kernel.mk
index 9a177b17..bdb1dc0c 100644
--- a/common/build/kernel.mk
+++ b/common/build/kernel.mk
@@ -150,11 +150,30 @@ define build_dtb
         dtbs
 endef

 $(KERNEL_BIN): $(KERNEL_CONFIG) $(TARGET_KERNEL_SRC) | $(KERNEL_OUT)
        $(hide) echo "Building $(KERNEL_ARCH) $(KERNEL_VERSION) kernel ..."
        $(hide) PATH=$$PATH $(MAKE) -C $(TARGET_KERNEL_SRC) mrproper
        $(call build_kernel,$(KERNEL_NAME))
        $(call build_kernel,modules)
+       $(hide) echo "building LWB module drivers"
+       $(MAKE) -C laird/backport ARCH=$(KERNEL_ARCH) \
+               CROSS_COMPILE="$(KERNEL_CROSS_COMPILE_WRAPPER)" \
+               KLIB_BUILD=$(realpath $(KERNEL_OUT)) defconfig-lwb5p
+       $(MAKE) -C laird/backport ARCH=$(KERNEL_ARCH) \
+               CROSS_COMPILE="$(KERNEL_CROSS_COMPILE_WRAPPER)" \
+               KLIB_BUILD=$(realpath $(KERNEL_OUT))
+
        $(call build_dtb); \
         for dtsplat in $(TARGET_BOARD_DTS_CONFIG); do \
                 DTB_NAME=`echo $$dtsplat | cut -d':' -f2`; \

(note that our kernel resides in ./vendor/<devkit vendor name>/kernel_imx. Adjust the KLIB_BUILD parameter as appropriate)

The first invocation of make will configure the for appropriate defconfig you specify. The second will actually create the device driver modules.

Note when the modules are compiled, both wireless and bt modules are created.

  • compat.ko
  • cfg80211.ko
  • brcmutil.ko
  • brcmfmac.ko

Kernel defconfig

ensure your kernel is built for using modules:

CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y

ensure the default cfg80211 is built as a module for the kernel (this version will not be used)

CONFIG_CFG80211=m

init.rc additions

Choose the appropriate 2 digit regulatory domain for the regdomain entry. Example is FCC

insmod vendor/lib/modules/compat.ko
insmod vendor/lib/modules/cfg80211.ko
insmod vendor/lib/modules/brcmutil.ko
insmod vendor/lib/modules/brcmfmac.ko regdomain="US"

init.rc changes/additional

# Prepare for wifi
    setprop wifi.interface wlan0
    setprop wifi.concurrent.interface p2p0

service wpa_supplicant /vendor/bin/hw/wpa_supplicant \
    -Dnl80211 -iwlan0 -c/vendor/etc/wifi/wpa_supplicant.conf \
    -O/data/vendor/wifi/wpa/sockets \
    -e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0
    class main
    socket wpa_wlan0 dgram 660 wifi wifi
    disabled
    oneshot

service dhcpcd_wlan0 /system/bin/dhcpcd -aABDKL
    class main
    disabled
    oneshot

service dhcpcd_p2p /system/bin/dhcpcd -aABKL
    class main
    disabled
    oneshot

service iprenew_wlan0 /system/bin/dhcpcd -n
    class main
    disabled
    oneshot

service iprenew_p2p /system/bin/dhcpcd -n
    class main
    disabled
    oneshot

BoardConfig.mk

BOARD_WLAN_DEVICE                := bcmdhd
BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_bcmdhd
BOARD_WPA_HOSTAPD_PRIVATE_LIB    := lib_driver_cmd_bcmdhd
BOARD_HAVE_BLUETOOTH             := true
BOARD_HAVE_BLUETOOTH_BCM         := true
BOARD_VENDOR_KERNEL_MODULES += \
	laird/backport/compat/compat.ko \
	laird/backport/net/wireless/cfg80211.ko \
	laird/backport/drivers/net/wireless/broadcom/brcm80211/brcmutil/brcmutil.ko \
	laird/backport/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko

Your device.mk

Add bluetooth options to product_packages

PRODUCT_PACKAGES += \
    android.hardware.bluetooth@1.0-impl \
    android.hardware.bluetooth@1.0-service \
    bt_vendor.conf \
    libbt-vendor

Firmware

Each of the LWB family’s firmware files contains several different firmware files, each of which needs to be added to the PRODUCT_COPY_FILES entry. Here is an example showing all the possible firmware files. You should only include the files from your firmware package.

In the ‘placement of code and firmware in AOSP’ section above, you un-tared the specific firmware for your usage.

add the appropriate firmware files for your radio to the device.mk file: (use the symlink name)

(modify the interface as necessary):
PRODUCT_COPY_FILES += \
  laird/lib/firmware/brcm/BCM4335C0.hcd:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/BCM4335C0.hcd \
  laird/lib/firmware/brcm/BCM43430A1.hcd:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/BCM43430A1.hcd \
  laird/lib/firmware/brcm/brcmfmac4339-sdio.bin:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac4339-sdio.bin \
  laird/lib/firmware/brcm/brcmfmac4339-sdio.txt:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac4339-sdio.txt \
  laird/lib/firmware/brcm/brcmfmac43430-sdio.bin:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac43430-sdio.bin \
  laird/lib/firmware/brcm/brcmfmac43430-sdio.clm_blob:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac43430-sdio.clm_blob \
  laird/lib/firmware/brcm/brcmfmac43430-sdio.txt:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac43430-sdio.txt \
  laird/lib/firmware/brcm/brcmfmac4373-sdio.txt:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac4373-sdio.txt \
  laird/lib/firmware/brcm/brcmfmac4373-sdio.clm_blob:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac4373-sdio.clm_blob \
  laird/lib/firmware/brcm/brcmfmac4373-sdio.bin:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac4373-sdio.bin \
  laird/lib/firmware/brcm/BCM4373A0.hcd:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/BCM4373A0.hcd \
  laird/lib/firmware/brcm/BCM4373A0-04b4-640c.hcd:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/BCM4373A0-04b4-640c.hcd \
  laird/lib/firmware/brcm/BCM4373A0.hcd:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/BCM4373A0.hcd \
  laird/lib/firmware/brcm/BCM4373A0-sdio-div.hcd:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/BCM4373A0-sdio-div.hcd \
  laird/lib/firmware/brcm/BCM4373A0-sdio-sa.hcd:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/BCM4373A0-sdio-sa.hcd \
  laird/lib/firmware/brcm/brcmfmac4373.bin:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac4373.bin \
  laird/lib/firmware/brcm/brcmfmac4373.clm_blob:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac4373.clm_blob \
  laird/lib/firmware/brcm/brcmfmac4373-clm-div.clm_blob:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac4373-clm-div.clm_blob \
  laird/lib/firmware/brcm/brcmfmac4373-clm-sa.clm_blob:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac4373-clm-sa.clm_blob \
  laird/lib/firmware/brcm/brcmfmac4373-div.txt:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac4373-div.txt \
  laird/lib/firmware/brcm/brcmfmac4373-sa.txt:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac4373-sa.txt \
  laird/lib/firmware/brcm/brcmfmac4373-sdio-prod.bin:$(TARGET_COPY_OUT_VENDOR)/firmware/brcm/brcmfmac4373-sdio-prod.bin \

SE policy file for WiFi HAL

ensure the contents of the /device/$(vendor)/sepolicy file are set:

$ cat hal_wifi_default.te
allow hal_wifi_default sysfs:file { write };

vndbinder_use(hal_wifi_default)

allow hal_wifi_default kernel:system module_request;
binder_call(hal_wifi_default, system_server)

allow hal_wifi_default system_server:binder {call transfer};
allow hal_wifi_default self:udp_socket {create ioctl create_socket_perms};
allow hal_wifi_default init:unix_stream_socket connect;
allow hal_wifi_default property_socket: sock_file write;

#mark as permissive domain
#permissive hal_wifi_default;

# allow hal_wifi_default access /data/misc/wifi
allow hal_wifi_default wifi_data_file:dir create_dir_perms;
allow hal_wifi_default wifi_data_file:dir create_file_perms;
allow hal_wifi_default wifi_data_file:dir rw_dir_perms;

allow hal_wifi_default wifi_data_file:file create_file_perms;
allow hal_wifi_default wifi_data_file:file rw_file_perms;

Bluetooth integration

add the bt_config attribute for Bluetooth Java layer in the configuration file in the following path: <aosp_root>/device/${vendor}/${device}/overlay/framework/base/core/res/res/values/config.xml (your path may vary)

--- a/overlay/frameworks/base/core/res/res/values/config.xml
+++ b/overlay/frameworks/base/core/res/res/values/config.xml
@@ -74,7 +74,7 @@
     <!-- the 6th element indicates boot-time dependency-met value. -->
     <string-array translatable="false" name="networkAttributes">
         <item>"wifi,1,1,1,-1,true"</item>
+        <item>"bluetooth,7,7,2,-1,true"</item>
         <item>"ethernet,9,9,2,-1,true"</item>
     </string-array>

Add sepolicy for the Bluetooth modules:

create or add the hal_bluetooth_default.te file under the sepolicy directory as:

$ cat hal_bluetooth_default.te
allow hal_bluetooth_default sysfs:file { write };
#allow hal_bluetooth_default bluetooth_data_file:file { write read append getattr };
allow hal_bluetooth_default hal_bluetooth_default:unix_stream_socket { ioctl };

allow hal_bluetooth_default sysfs_rfkill:file { write };
# connect to the UART
allow hal_bluetooth_default wcnss_filter:unix_stream_socket {connectto};

# vendor.wc_transport.start_hci and friends
set_prop(hal_bluetooth_default, wc_prop)
set_prop(hal_bluetooth_default, vendor_bluetooth_prop)

# talk to system_server to set priority
allow hal_bluetooth_default fwk_scheduler_hwservice:hwservice_manager {find};
allow hal_bluetooth_default system_server:binder {call};


# Use bluetooth device
allow hal_bluetooth_default hci_attach_dev:chr_file rw_file_perms;
allow hal_bluetooth_default bluetooth_data_file:dir {rw_dir_perms add_name remove_name};
allow hal_bluetooth_default hci_attach_dev:chr_file {open read write ioctl};

In the same directory. update the sepolicy/system_server.te file:

--- a/sepolicy/system_server.te
+++ b/sepolicy/system_server.te
@@ -28,3 +28,5 @@ allow system_server shell_data_file:file { map };
 allow system_server graphics_device:dir { search };
 allow system_server graphics_device:chr_file { open read ioctl };
 allow system_server sysfs_extcon:file { getattr open read };
+
+dontaudit system_server bluetooth:file write;

Also in the same directory, modify file_contexts to include the UART you are using for BT. In this example, we use ttymxc3:

+ /dev/tty??? if using UART. Check your system to determine the port name

--- a/sepolicy/file_contexts
+++ b/sepolicy/file_contexts
@@ -15,6 +15,7 @@
 /dev/dri/controlD65             u:object_r:graphics_device:s0
 /dev/dri/renderD128             u:object_r:gpu_device:s0
 /dev/dri/renderD129             u:object_r:gpu_device:s0
+/dev/ttymxc3                    u:object_r:hci_attach_dev:s0

update uevent permissions

modify the uevent.rc file for for the appropriate port: (as with earlier entries, your port name will likely be different. See above section)

--- a/ueventd.freescale.rc
+++ b/ueventd.freescale.rc
@@ -1,6 +1,6 @@
 /dev/block/platform/30b50000\.usdhc/by-name/presistdata 0600   system     system
 /dev/block/platform/30b40000\.usdhc/by-name/presistdata 0600   system     system
+/dev/ttymxc3              0660   bluetooth  bluetooth
 /dev/snd/*                0660   system     audio
 /dev/video*               0660   system     camera
 /dev/mxc_hantro           0660   media      drmrpc

update the UART port in broadcom/libbt/conf/fsl/mek_8q/bt_vendor.conf

$ cat broadcom/libbt/conf/fsl/mek_8q/bt_vendor.conf
# UART device port where Bluetooth controller is attached
UartPort = /dev/ttymxc3

# Firmware patch file location
#FwPatchFilePath = /vendor/firmware/brcm

#FwPatchFileName = CYW4354A2.1CX.hcd

add bluetooth to manifest.xml

--- a/manifest.xml
+++ b/manifest.xml
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="hidl">
+        <name>android.hardware.bluetooth</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IBluetoothHci</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl">
         <name>android.hardware.boot</name>
         <transport>hwbinder</transport>

revert bt initialization timeout from new 2.9 seconds back to 8 second

system/bt/hci/src/hci_layer.cc

 // Using a define here, because it can be stringified for the property lookup
 // Default timeout should be less than BLE_START_TIMEOUT and
 // having less than 3 sec would hold the wakelock for init
-#define DEFAULT_STARTUP_TIMEOUT_MS 2900
+//#define DEFAULT_STARTUP_TIMEOUT_MS 2900
+#define DEFAULT_STARTUP_TIMEOUT_MS 8000
 #define STRING_VALUE_OF(x) #x

 // Abort if there is no response to an HCI command.