This guide provides a step by step explanation of what is involved in adding a new WiFi driver and making a new WiFi card work well in a custom Android build. (This guide was written for Android 4.1 but should be applicable to previous Android releases and hopefully future releases.)
Contents
As the following figure, Android wireless architecture can be divided into three parts:
Java Framework(WifiManager, WifiMonitor etc..),
HAL(wifi.c,wpa_supplicant,netd)
kernel space modules(wireless stack, wifi drivers)
Java Framework communicate with wpa_supplicant using native interface (wifi.c). Wpa_supplicant and netd uses wireless extension or nl80211 to control WiFi drivers.
Usually WiFi driver is provided as a kernel module. There are mainly two types of Android WiFi architecture:nl80211 and wext. With the implementation of nl80211/cfg80211 many wireless drivers in main line kernel support nl80211 interface instead of wireless extension.
For different vendors’ WiFi drivers, writing one Android.mk to add its compile into Android is what you should do. Here take atheros’s AR6kl as an example:
ath6kl_module_file :=drivers/net/wireless/ath/ath6kl/ath6kl_sdio.ko
$(ATH_ANDROID_SRC_BASE)/$(ath6kl_module_file):$(mod_cleanup) $(TARGET_PREBUILT_KERNEL) $(ACP)
$(MAKE) -C $(ATH_ANDROID_SRC_BASE) O=$(ATH_LINUXPATH) ARCH=arm CROSS_COMPILE=$(ARM_EABI_TOOLCHAIN)/arm-eabi- KLIB=$(ATH_\
LINUXPATH) KLIB_BUILD=$(ATH_LINUXPATH)
$(ACP) -fpt $(ATH_ANDROID_SRC_BASE)/compat/compat.ko $(TARGET_OUT)/lib/modules/
$(ACP) -fpt $(ATH_ANDROID_SRC_BASE)/net/wireless/cfg80211.ko $(TARGET_OUT)/lib/modules/
include $(CLEAR_VARS)
LOCAL_MODULE := ath6kl_sdio.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/modules
LOCAL_SRC_FILES := $(ath6kl_module_file)
include $(BUILD_PREBUILT)
In Android’s external directory, there are two wpa_supplicant_* projects. For wext-based wifi driver, wpa_supplicant_6 can be used. For nl80211-based WiFi driver, wpa_supplicnat_8 can only be used. But if WiFi vendors supply their own customized wpa_supplicant, it will be much easier to debug the communication between wpa_supplicant and WiFi drivers. No matter which supplicant you choose, just control their compile in your BoardConfig.mk.
Take atheros’s ath6kl as an example:
ifeq ($(BOARD_WLAN_VENDOR),ATHEROS)
BOARD_WLAN_DEVICE := ar6003
BOARD_HAS_ATH_WLAN := true
WPA_SUPPLICANT_VERSION := VER_0_8_ATHEROS
WIFI_DRIVER_MODULE_PATH := "/system/lib/modules/ath6kl_sdio.ko"
WIFI_DRIVER_MODULE_NAME := "ath6kl_sdio"
WIFI_DRIVER_MODULE_ARG := "suspend_mode=3 wow_mode=2 ar6k_clock=26000000 ath6kl_p2p=1"
WIFI_DRIVER_P2P_MODULE_ARG := "suspend_mode=3 wow_mode=2 ar6k_clock=26000000 ath6kl_p2p=1 debug_mask=0x2413"
WIFI_SDIO_IF_DRIVER_MODULE_PATH := "/system/lib/modules/cfg80211.ko"
WIFI_SDIO_IF_DRIVER_MODULE_NAME := "cfg80211"
WIFI_SDIO_IF_DRIVER_MODULE_ARG := ""
WIFI_COMPAT_MODULE_PATH := "/system/lib/modules/compat.ko"
WIFI_COMPAT_MODULE_NAME := "compat"
WIFI_COMPAT_MODULE_ARG := ""
endif
then you need to provide a proper wpa_supplicant.conf for your device. wpa_supplicant.conf is very important because the control socket for android is specified in this file(ctrl_interface=). This file should be copied to /system/etc/wifi.
Minimum required config options in wpa_supplicant.conf :
There are two different ways in which wpa_supplicant can be configured, one is to use a "private" socket in android namespace, created by socket_local_client_connect() function in wpa_ctrl.c and another is by using a standard UNIX socket.
Android private socket
ctrl_interface=wlan0
update_config=1
- Unix standard socket
ctrl_interface=DIR=/data/system/wpa_supplicant GROUP=wifi
update_config=1
Here what you should do is modifying some codes like wifi_load_driver and wifi_unload_driver.
For Broadcom or CSR’s wifi driver, you can directly use the original wifi.c. But for atheros’s ath6kl driver, there are total three .ko modules to install. So some micro variables and codes need to be changed to adapt it.
If you have configured to use android private socket, you should do like this:
service wpa_supplicant /system/bin/wpa_supplicant -Dwext -iwlan0 -c / data/misc/wifi /wpa_supplicant.conf
socket wpa_wlan0 dgram 660 wifi wifi
disabled
oneshot
or if you have configured to use unix standard socket, you should do like this:
service wpa_supplicant /system/bin/wpa_supplicant -Dwext -iwlan0 -c/data/misc/wifi/wpa_supplicant.conf
disabled
oneshot
If WiFi driver is not “wext” but “nl80211”, you should change it to –Dnl80211.
For dhcpcd, you should lunch it like the following:
service dhcpcd_wlan0 /system/bin/dhcpcd -ABKL
class late_start
disabled
oneshot
The parameters “-ABKL” can largely enhance wifi connection speed. About what “ABKL” stand for, you can refer to dhcpcd’s GNU manual.
By default wpa_supplicant is set to MSG_INFO that doesn't tell much.
To enable more messages:
modify common.c and set wpa_debug_level = MSG_DEBUG
modify common.h and change #define wpa_printf from if ((level) >= MSG_INFO) to if ((level) >= MSG_DEBUG)
3. WiFi driver’s softmac.
For most vendors’ WiFi driver, the mac address is fixed. We should add one softmac rule to let WiFi driver’s mac is unique for each board.
Hi jodipaul, how to support SDIO WiFi in imx6,can you give the detailed steps?
Thank you.
Hi Jodi Paul, how to support wl12xx SDIO WiFi in JB4.3 with imx6q, can you give the detailed steps or patches?
Thank you.
Dear Jianzheng Zhou,
Could you please tell me why sdio_reset_comm function is not present in imx 3.10.17 Kernel.
While inserting module
its giving error
insmod bcmdhd.ko
Error: could not insert module bcmdhd.ko: Unknown symbol in module
bcmdhd: Unknown symbol sdio_reset_comm (err 0)
Do you have patch for this?
Hi Alam
I think you can try below patch for your bcmdhd driver:
|=============================================================================|
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
index 181cf47..22cef80 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
@@ -59,7 +59,7 @@ static void IRQHandler(struct sdio_func *func);
static void IRQHandlerF2(struct sdio_func *func);
#endif /* !defined(OOB_INTR_ONLY) */
static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
-extern int sdio_reset_comm(struct mmc_card *card);
+static int sdio_reset_comm(struct mmc_card *card);
#define DEFAULT_SDIO_F2_BLKSIZE 512
#ifndef CUSTOM_SDIO_F2_BLKSIZE
@@ -92,6 +92,12 @@ DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data);
+/* workaround to simply return 0 as suggested by Broadcom */
+static int sdio_reset_comm(struct mmc_card *card)
+{
+ return 0;
+}
+
static int
sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
{
|=============================================================================|
BRs,
Haoran
Hi all,
Can anyone help me with some document or starting point for enabling wifi in I.MX6 sabreauto with android_L5.0.0_1.0.0 BSP.
I am using Netgear N150 WNA1100 wireless USB adapter.
I have tried to enable the ATH9k configuration using kernel makeconfig
CONFIG_ATH_COMMON=m
CONFIG_ATH_CARDS=m
# CONFIG_ATH_DEBUG is not set
CONFIG_ATH9K_HW=m
CONFIG_ATH9K_COMMON=m
CONFIG_ATH9K_BTCOEX_SUPPORT=y
CONFIG_ATH9K=m
CONFIG_ATH9K_AHB=y
CONFIG_ATH9K_DEBUGFS=y
CONFIG_ATH9K_MAC_DEBUG=y
CONFIG_ATH9K_LEGACY_RATE_CONTROL=y
CONFIG_ATH9K_HTC=m
CONFIG_ATH9K_HTC_DEBUGFS=y
Below is the log generated when ever i connect the netgear device:
usb 2-1:New USB device found, idvendor=0846, idproduct=9030
usb 2-1:New USB device strings: Mfr=16, Product=32, SerialNumber=48
usb 2-1:Product:WNA1100
usb 2-1:Manufacturer:NETGEAR WNA
usb 2-1:SerialNumber:12345
Thanks and Regards,
Arun S