How to Support New WiFi Card in Android

cancel
Showing results for 
Search instead for 
Did you mean: 

How to Support New WiFi Card in Android

How to Support New WiFi Card in Android


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.

Labels (2)
Tags (2)
Comments

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

Version history
Revision #:
1 of 1
Last update:
‎10-10-2012 02:53 AM
Updated by: