Introduction

The Android kernel uses a TI-provided 802.11 driver. This driver is GPLed, however it does not use the standard Linux wireless stack. Kalle Valo of Nokia has written a mac80211-based driver, wl12xx, which was mainlined in 2.6.31, and I have written the SDIO interface logic, likely to go in for 2.6.32.

Most people should just stick with the driver that comes with the ADP1, as it’s rather painful to switch drivers and there are few benefits to using wl12xx at this time. However, in the interest of having a mainlined wifi driver on the device, here are a few notes on how to install and use wl12xx.

There is a lot of room for streamlining the process here, but this is more or less what I’ve arrived at. Please let me know if there are any errors.

I assume you already have ADP v1.5 installed since the kernel needs a recent userspace. I also have busybox installed in my path, but I’ve left out any manual path setup for brevity’s sake.

Patches

These patches are also linked inline:

Android wireless setup

Android uses a wpa_supplicant build with a custom driver for the TI vendor driver. The UI communicates with this lower level via the Java class android.net.wifi.WifiNative, which is implemented in android_net_wifi_Wifi.cpp. This, in turn, uses functions in libhardware_legacy/wifi/wifi.c to interact with the wpa_supplicant control socket located on the device in /dev/socket/wpa_tiwlan0. Android handles some additional commands not included in the stock wpa_supplicant, defined in external/wpa_supplicant/ctrl_iface.c.

Note, the default wpa_supplicant drivers (e.g. -Dwext), will not do anything useful for the custom Android commands, so the UI will not work properly at this time. My patch for wpa_supplicant adds a few stubs to the nl80211 driver, but it is incomplete.

Base Environment

The Android code drop described here includes a kernel tree as well as a cross-compiler toolchain and userland. You will need to build this first to create all the libraries for building userspace utilities.

Building the MSM kernel

I prefer to clone my kernel directly rather than using the repo tool, Also I use the 2.6.29 version because it is compatible with compat-wireless, and the precompiled tiwlan driver won’t load so it doesn’t get in the way.

% git clone git://android.git.kernel.org/kernel/msm.git
% cd msm
% git checkout -b android-msm-2.6.29 origin/android-msm-2.6.29

Apply this patch to create a new module called msm_wifi. This module sets GPIOs appropriately to power up the wifi module and implement virtual card-select; it needs to be loaded for wl1251_sdio to successfully probe the device.

You should configure the kernel with at least SDIO and MAC80211 support (my .config). Put the arm toolchain in your path and do:

% make ARCH=arm CROSS_COMPILE=arm-none-eabi-

Building compat-wireless

Current compat-wireless contains everything you need to build wl1251_sdio. Download it here.

I use a short script to take care of cross-compiling compat-wireless:

make-arm.sh
#!/bin/bash
DIR=/home/bob/ext/android/msm
XGCC=/home/bob/projects/xgcc
export PATH="$XGCC/arm-2008q3/bin/:$PATH"
make ARCH=arm CROSS_COMPILE=arm-none-eabi- KLIB=$DIR KLIB_BUILD=$DIR "$@"

Once built, I use the following script to copy the modules to the device:

copy_modules.sh
#!/bin/sh
compat=compat-wireless
adb="bin/adb"
for i in $compat/net/mac80211/mac80211.ko \
         $compat/net/wireless/cfg80211.ko \
         $compat/drivers/net/wireless/wl12xx/wl1251_sdio.ko \
         $compat/drivers/net/wireless/wl12xx/wl1251.ko; do
    $adb push $i /sdcard/modules/
done
$adb push msm/arch/arm/mach-msm/msm_wifi.ko /sdcard/modules/

Also, a script on the phone itself makes it easy to load everything without setting up modules.dep properly:

load.sh
insmod cfg80211.ko
insmod mac80211.ko
insmod wl1251.ko
insmod wl1251_sdio.ko
insmod msm_wifi.ko

Getting firmware files

wl12xx needs two firmware files. One includes the standard firmware which is the same for all devices, and another that includes calibration data that is specific to each individual device. To get them in the right place, boot the normal kernel. Turn on the wifi to load the TI driver, then do:

% adb shell
$ su
# mount -o remount,rw /
# cd /system/etc/firmware
# ln -s ../wifi/Fw1251r1c.bin wl1251-fw.bin
# cat /proc/calibration > wl1251-nvs.bin
# mount -o remount,ro /

Booting the device

In my opinion, the easiest way to load a custom kernel is to unpack the ramdisk image from the 1.5 firmare package, then boot with the self-compiled zImage. To get the ramdisk, I use the unpack-bootimg.pl script on the boot.img from the Android 1.5 system image zip archive:

% ./unpack-bootimg.pl boot.img
kernel written to boot.img-kernel.gz
ramdisk written to boot.img-ramdisk.cpio.gz
[...]
% gunzip boot.img-ramdisk.cpio.gz

To boot the kernel, put the phone in fastboot mode. Plug the phone into USB, then hold down the back-arrow while turning the phone on. This should bring up the boot loader (robots on skateboards) with the string "FASTBOOT" in the center. Now run the fastboot tool:

# fastboot boot msm/arch/arm/boot/zImage boot.img-ramdisk.cpio
creating boot image...
creating boot image - 1859584 bytes
downloading 'boot.img'... OKAY
booting... OKAY

You won’t see anything for a minute or so, then the phone will reboot. If you have all the proper tools installed (see below) and a wpa_supplicant.conf, you can then try loading the modules and associating:

% adb shell
$ cd /sdcard/modules/
# su
# sh load.sh
# ifconfig wlan0 up
# wpa_supplicant -B -Dnl80211 -iwlan0 -c /sdcard/wpa_supplicant.conf
# dhcpcd wlan0

If all goes well, wlan0 will have associated with your AP and you’re up and running.

Userland tools

wpa_supplicant - WEXT

You can rebuild the wpa_supplicant that comes with the Android build environment to also support wl1251 (and any other mac80211 driver) by including the wireless extensions driver. To do so, from the toplevel Android directory, edit external/wpa_supplicant/Makefile and add the following lines to the mkconfig target:

echo CONFIG_DRIVER_WEXT=y >> .config
echo CONFIG_WIRELESS_EXTENSION=y >> .config

Then build the supplicant:

% make wpa_supplicant

However, WEXT is old and busted and NL80211 is the new hotness, so read on to build one that supports nl80211.

wpa_supplicant - nl80211

Here’s how to build a recent, dynamically-linked wpa_supplicant from git. Note it does not include support for the tiwlan0 driver that works with the vendor driver. The SHA-1s noted below are known to work but newer ones might also suffice.

libnl

Grab the tree for libnl:

% git clone git://git.kernel.org/pub/scm/libs/netlink/libnl.git
% cd libnl
% git checkout -b android 2e6ded94f453ed725381b1fae5dcaa6c7fcfb9b8
Switched to a new branch 'android'

Then apply this patch. Be sure to edit lib/Makefile and change ANDROID to point to your android build environment.

% cd lib
% make

Hopefully, make completed successfully and spat out libnl.so. If not, good luck figuring it out. Wrestling with the include order to satisfy the cross compiler and bionic libc is "fun."

This needs to go into the /system/lib/ directory on the device because the library search path is hard-coded. You can use the mount -o remount,rw trick to get it there from the sdcard.

wpa_supplicant

Now get wpa_supplicant (part of hostap package):

% git clone git://w1.fi/srv/git/hostap.git
% cd hostap
% git checkout -b android f6190d376d710b5c60665be5bbfdfed315cfcdd0
Switched to a new branch 'android'

Then apply this patch. Again, edit wpa_supplicant/config_android to configure the ANDROID and LIBNL paths appropriately.

% cd wpa_supplicant
% cp config_android .config
% make

You now have a wpa_supplicant binary dynamically linked against bionic libc and libnl.so. Unlike the android fork, it does not include the custom TI supplicant driver, so it can only be used with wl12xx or other native Linux drivers.

Either version of wpa_supplicant needs a config file like the following to connect to your AP:

/sdcard/wpa_supplicant.conf
ctrl_interface=/dev/socket/wpa_tiwlan0
network={
      ssid="my-ssid"
      key_mgmt=WPA-PSK
      psk="my-key"
}

iw

iw is an iwconfig replacement using netlink. You must first build and install libnl.so as above.

% git clone http://git.sipsolutions.net/iw.git
% cd iw
% git checkout -b android 528685164d23e0dd474ad788fcd96bb350b2788a
Switched to a new branch 'android

Then apply this patch. Once more, edit the Makefile for ANDROID and LIBNL, then do:

% make -f Makefile.arm