How to Support New WiFi Card in Android

Document created by waterzhou Employee on Oct 10, 2012Last modified by Jodi Paul on May 9, 2013
Version 10Show Document
  • View in full screen mode


Introduction

 

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

    1. Understand how Android WiFi works
    2. Port WiFi driver.
    3. Compile a proper wpa_supplicant in your BoardConfig.mk
    4. Modify your wifi.c in HAL.
    5. Launch wpa_supplicant and dhcpcd services in init.rc.
    6. Several debug tips.

 

Understand How Android WiFi Works

 

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.

 

wifi.bmp

 

Port WiFi driver

 

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)


Compile a proper wpa_supplicant in your BoardConfig.mk

 

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

 

Modify your wifi.c in HAL

 

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.

 

Launch wpa_supplicant and dhcpcd services in init.rc

 

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.

 

Several debug tips

 

    1. Incorrect permissions will result in wpa_supplicant not being able to create/open the control socket andlibhardware_legacy/wifi/wifi.c won't connect.
      Since Google modified wpa_supplicant to run as wifi user/group the directory structure and file ownership should belong to wifi user/group (see os_program_init() function in wpa_supplicant/os_unix.c ).

      Otherwise errors like:
      E/WifiHW  (  ): Unable to open connection to supplicant on "/data/system/wpa_supplicant/wlan0": No such file or directory will appear.

      Also wpa_supplicant.conf should belong to wifi user/group because wpa_supplicant will want to modify this file.
    2. How to Enable debug for wpa_supplicant.

              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.

2 people found this helpful

Attachments

    Outcomes