原文地址 http://blog.csdn.net/robinyeung/article/details/7265640
一、wifi基本架構(gòu)
1、開源代碼移植部分(external目錄下)
wireless_tools、wpa_supplicant、wpa_supplicant_6(后兩項已經(jīng)移植過)
生成庫libwpaclient.so和守護(hù)進(jìn)程wpa_supplicant及iwconfig、iwlist等相關(guān)的測試程序
2、hardware/libhardware_legary/wifi/wifi.c是wifi管理庫
生成libnetutils.so
同時會和wpa_supplicant守護(hù)進(jìn)程通信
3、JNI部分
frameworks/base/core/jni/android_net_wifi_Wifi.cpp 這個是無線connect、scan方面的調(diào)用
frameworks/base/core/jni/android_net_NetUtils.cpp 這個是管理網(wǎng)絡(luò)方面的工具,如dhcp、route、net en/unable等
4、JAVA部分
frameworks/base/services/java/com/android/server/
frameworks/base/wifi/java/android/net/wifi/
frameworks/base/core/java/android/net 這個是管理網(wǎng)絡(luò)的工具,調(diào)用第三條的第二個jni
5、WIFI Settings位于
packages/apps/Settings/src/com/android/settings/wifi/
6、WIFI驅(qū)動模塊 ????rt5370sta.ko(此驅(qū)動兼容使用ralink的好多種設(shè)備驅(qū)動,具體可以查看USB_DEVICE_ID)
wpa_supplicant通過wireless_ext 接口和驅(qū)動通信
7、WIFI 硬件模塊
D-Link DWA-125 芯片:ralink RT3070
二、wifi開發(fā)記錄
1、5370驅(qū)動編譯安裝及使用過程
set the "MODE = STA" in Makefile and chose the TARGET to Linux by set "TARGET = LINUX"
set 'HAS_WPA_SUPPLICANT=y' and 'HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=y'
#wpa_supplicant -Dwext -iwlan0 -c wpa_supplicant.conf -d (-c這里需要指定下wpa_supplicant.conf的路徑)
wpa_supplicant.conf 內(nèi)容:
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
network={
ssid="home"
scan_ssid=1
key_mgmt=WPA-PSK
psk="very secret passphrase"
} // 這個地方的大括號中的內(nèi)容可在settings中點擊選擇某個ap后自動生成
#sudo su (android平臺需要自己添加腳本編譯,和這里寫的有差異)
#make clean
#make
#make install
#modprobe rt5370sta
#ifconfig wlan0 up
#iwconfig wlan0
#iwlist wlan0 scan 這時候已經(jīng)可以掃描wi-fi網(wǎng)絡(luò)了
下面是dhcpcd wlan0即可。
2、幾個可執(zhí)行程序:wpa_supplicant,wpa_cli等。wpa_supplicant是核心程序,它和wpa_cli的關(guān)系就是服務(wù)和客戶端的關(guān)系:后臺運(yùn)行wpa_supplicant,可以使用wpa_cli來搜索、設(shè)置、和連接網(wǎng)絡(luò)等,這兩個可執(zhí)行程序很重要
在android中主要是Settings這個屬于system的進(jìn)程調(diào)用的libhardware_legecy庫中的wifi.c文件和wpa_supplicant通信,同時也調(diào)用了wpa_supplicant中提供的libwpa_client.so庫,這兩個進(jìn)程間通過socket通信收發(fā)數(shù)據(jù)來得到當(dāng)前狀態(tài),同時也是通過wifi.c來啟動和停止init.rc中的wpa_supplicant進(jìn)程。
dhcpcd用來自動獲取ip。
iwconfig iwevent iwgetid iwlist iwpriv iwspy這幾個是測試命令,可用來測試wifi當(dāng)前的情況,以及scan ap等。
3、以上是命令測試過程,下面進(jìn)行代碼的修改部分說明(broadcom BCM7231)
wpa_supplicant 和wpa_cli原生android2.3已經(jīng)移植,但是沒有wireless tool工具,需要將工具移植進(jìn)來,
不過這些工具相對都比較容易移植,不再詳述,下載源碼位置如下
然后從驅(qū)動開始修改起
1)修改5370驅(qū)動
設(shè)備名include/rtmp_def.h 修改兩個宏定義從ra0修改為wlan0;
LINUX_SRC=... (android的kernel位置)
ifeq($(PLATFORM),BCM7431)
LINUX_SRC= ${ANDROID_PATH}/kernel #修改path為你的android目錄
endif
驅(qū)動編譯后會生成兩個文件:RT5370STA.ko 和RT2870STA.dat,后面
會看到需要拷貝這兩個文件到系統(tǒng)中。
ioctl 驅(qū)動代碼接口在os/linux/sta_ioctl.c 及 sta/sta_cfg.c中,如果遇到一些錯誤,一般在這里都能查找到.
2)把rt5370sta.ko拷貝到.../lib/modules目錄中
- include$(CLEAR_VARS)
- LOCAL_MODULE := rt5370sta.ko
- LOCAL_MODULE_TAGS:= user
- LOCAL_MODULE_CLASS:= SHARED_LIBRARIES
- LOCAL_MODULE_PATH:= $(TARGET_OUT_SHARED_LIBRARIES)/modules
- LOCAL_SRC_FILES:= ${RT5370_PATH}/rt5370sta.ko #PATH
- include$(BUILD_PREBUILT)
3) 查看wifi.c文件ko路徑及名字是否正確,若不正確需要修改正確
4) 修改init.rc文件
chmod 0771 /system/etc/wifi wifi wifi
chmod 0660 /system/etc/wifi/wpa_supplicant.conf
chown wifi wifi /system/etc/wifi/wpa_supplicant.conf
mkdir /data/misc/wifi 0771 wifi wifi
mkdir /data/misc/wifi/sockets 0771 wifi wifi
#wpa_supplicant socket
mkdir /data/system/ 0771 system system
mkdir /data/system/wpa_supplicant 0771 wifi wifi
mkdir /data/misc/dhcp 0771 system system
chmod 0777 /system/etc/dhcpcd/dhcpcd-run-hooks
chmod 0777 /data/misc/dhcp/
mountyaffs2 mtd@system /system ro remount
setprop wifi.interface wlan0
service wpa_supplicant /system/bin/wpa_supplicant -dd -Dwext -iwlan0 -c/system/etc/wifi/wpa_supplicant.conf
#group system wifi inet
disabled
oneshot
service dhcpcd_wlan0 /system/bin/dhcpcd wlan0 // 這里的service需要修改為dhcpcd_wlan0(android2.2 和2.3有差異,我這里是2.3),而不是dhcpcd!
group system dhcp
disabled
oneshot
5) 修改external/wpa_supplicant/driver_wext.c
這是為了避免wpa_supplicant與下層驅(qū)動通訊時出現(xiàn)ioctl[SIOCSIWPRIV]錯誤,因為現(xiàn)在大部分wifi模塊對SIOCSIWPRIV命令不處理,而這個命令要用于偵測wifi強(qiáng)度RSSI的,比較簡單的方法是在wifi驅(qū)動中增加個空函數(shù)或者修改調(diào)用的返回值為0。由于大多數(shù)模塊不支持SIOCSIWPRIV,所以目前采用修改調(diào)用的返回值的方法。修改:froyo\external\wpa_supplicant\driver_wext.c
wpa_driver_priv_driver_cmd()函數(shù)中:
// if((ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr)) < 0) {
//perror("ioctl[SIOCSIWPRIV]");
// }
// 如果這里不注釋掉,將導(dǎo)致系統(tǒng)不斷報錯??,錯誤為 IOCTL::unknownIOCTL's cmd = 0x00008b0c,我跟蹤了下代碼驅(qū)動中并沒有這個ioctl,
另外在wpa_supplicant的頭文件中也顯示未使用,但是在代碼中卻用了這個ioctl,所以必須把這段代碼刪除!
6) 修改android打開WIFI流程
經(jīng)測試5370模塊在ifconfig wlan0 down時配置
iwconfig wlan0 mode Managed會出錯,Android代碼中的配置過程也是這樣,表現(xiàn)就是關(guān)閉WIFI重新打開后掃描不到AP,修改:mips-gingerbread\frameworks\base\wifi\java\android\net\wifi\WifiStateTracker.java
- public void resetConnections(boolean disableInterface)
- if(disableInterface){
- //if(LOCAL_LOGD) Log.d(TAG, "Disabling interface");
- //NetworkUtils.disableInterface(mInterfaceName);
- } //此處若不修改將導(dǎo)致wifi關(guān)閉后再次開啟,scan不到ap!
#netcfg
lo UP 127.0.0.1 255.0.0.0 0x00000049
eth0 UP 10.20.112.46 255.255.255.0 0x00001043
wlan0 DOWN 0.0.0.0 0.0.0.0 0x00001002
#iwconfig wlan0 mode Managed
Error for wireless request "Set Mode" (8B06) :
SET failed on device wlan0 ; Network is down.
#iwconfig wlan0 nickname "RobinYeung"
Error for wireless request "Set Nickname" (8B1C) :
SET failed on device wlan0 ; Network is down.
上面java代碼的調(diào)用函數(shù)為:
- static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname)
- {
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_disable(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jint)result;
- }
此jni函數(shù)又調(diào)用了ifc_disable函數(shù),如下:
- int ifc_disable(const char *ifname)
- {
- int result;
-
- ifc_init(); // 調(diào)用socket函數(shù),得到fd
- result = ifc_down(ifname); // 通過ioctl設(shè)定到內(nèi)核
- ifc_set_addr(ifname, 0);
- ifc_close(); // 關(guān)閉fd
- return result;
- }
ifc_down函數(shù)
- int ifc_down(const char *name)
- {
- return ifc_set_flags(name, 0, IFF_UP);
- }
-
- static int ifc_set_flags(const char *name, unsigned set, unsigned clr)
- {
- struct ifreq ifr;
- ifc_init_ifr(name, &ifr);
-
- if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) return -1;
- ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set;
- return ioctl(ifc_ctl_sock, SIOCSIFFLAGS, &ifr);
- }
down時flags & fffffffe,然后通過ioctl 設(shè)定到kernel。
7) 創(chuàng)建wpa_supplicant.conf文件 在你的board配置目錄下MIPSAndroid_Phase2.1/bcm_mipsgingerbread20111129/AppLibs/opensource/android/src/mips-gingerbread/vendor/broadcom/bcm_platform/prebuilt創(chuàng)建一個wpa_supplicant.conf文件,輸入如下內(nèi)容:
ctrl_interface=DIR=/data/system/wpa_supplicant GROUP=wifi
update_config=1
ap_scan=1
8)修改board配置目錄下的AndroidBoard.mk
在MIPSAndroid_Phase2.1/bcm_mipsgingerbread20111129/AppLibs/opensource/android/src/mips-gingerbread/vendor/broadcom/bcm_platform/Android.mk 或AndroidBoard.mk下增加如下代碼:
include$(CLEAR_VARS)
LOCAL_MODULE:= wpa_supplicant.conf
LOCAL_MODULE_TAGS:= user
LOCAL_MODULE_CLASS:= ETC
LOCAL_MODULE_PATH:= $(TARGET_OUT_ETC)/wifi
LOCAL_SRC_FILES:= $(LOCAL_MODULE)
include$(BUILD_PREBUILT)
9)少了一個步驟,就是拷貝RT2870STA.dat到etc下
include $(CLEAR_VARS)
LOCAL_MODULE := RT2870STA.dat
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/Wireless/RT2870STA
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
10) make clean 然后
根據(jù)您的腳本build android or all
三、開發(fā)遇到的問題匯總 1、如果發(fā)現(xiàn)wifi當(dāng)前是開著的,而卻發(fā)現(xiàn)關(guān)機(jī)再重啟卻沒自動開啟的話,很有可能是飛行模式揉的貨!修改數(shù)據(jù)庫即可正常,如下:
- sqlite3 /data/data/com.android.providers.settings/databases/settings.db
- delete from system where name = 'airplane_mode_on';
- .exit
2、wi-fi信號強(qiáng)度問題
源碼位置2.2和2.3不同,2.2在frameworks/base/services/java/com/android/server/status/StatusBarPolicy.java
2.3在frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
2.3中單獨成為一個apk,叫SystemUI.apk, 從源碼位置也能看出來。更新wifi status bar部分代碼如下:
- else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
- action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION) ||
- action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
- updateWifi(intent); }
- private final void updateWifi(Intent intent) {
- final String action = intent.getAction();
- if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-
- final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
- WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
-
- if (!enabled) {
- // If disabled, hide the icon. (We show icon when connected.)
- mService.setIconVisibility("wifi", false);
- }
-
- } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
- final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
- false);
- if (!enabled) {
- mService.setIconVisibility("wifi", false);
- }
- } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
- int iconId;
-
- final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
- int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
- sWifiSignalImages[0].length);
- if (newSignalLevel != mLastWifiSignalLevel) {
- mLastWifiSignalLevel = newSignalLevel;
- if (mIsWifiConnected) {
- iconId = sWifiSignalImages[mInetCondition][newSignalLevel];
- } else {
- iconId = sWifiTemporarilyNotConnectedImage;
- }
- mService.setIcon("wifi", iconId, 0);
- }
- }
- }<span style="font-family: Arial, Verdana, sans-serif; white-space: normal; background-color: rgb(255, 255, 255); "> </span>
- <pre name="code" class="java"> /**
- * Calculates the level of the signal. This should be used any time a signal
- * is being shown.
- *
- * @param rssi The power of the signal measured in RSSI.
- * @param numLevels The number of levels to consider in the calculated
- * level.
- * @return A level of the signal, given in the range of 0 to numLevels-1
- * (both inclusive).
- */
- public static int calculateSignalLevel(int rssi, int numLevels) {
- if (rssi <= MIN_RSSI) {
- return 0;
- } else if (rssi >= MAX_RSSI) {
- return numLevels - 1;
- } else {
- int partitionSize = (MAX_RSSI - MIN_RSSI) / (numLevels - 1);
- return (rssi - MIN_RSSI) / partitionSize;
- }
- }
- </pre>
- <pre></pre>
- <pre name="code" class="html">I/WifiStateTracker( 1799): ----------getRssiApprox------------WifiNative.getRssiCommand():-20
- I/WifiStateTracker( 1799): ---------------------->newRssi:-20
- I/WifiStateTracker( 1799): ---------------------->newSignalLevel:3
- </pre><br>
- <span style="font-size:18px; color:#330099"> 根據(jù)log可發(fā)現(xiàn)level為-20,而根據(jù)計算公式算為 (-55 - (-100))/ 3 = 15;</span>
若rssi level = -20,那么結(jié)果為 (-20 - (-100))/ 15 = 5。
后來發(fā)現(xiàn)自己忽略了前面一個if語句,-20 明顯 > -55,將不進(jìn)入計算分支,而直接計算 4 - 1 = 3;
所以問題就解決了!
3、usb類型的wi-fi設(shè)備插拔導(dǎo)致的界面死掉的問題解決方案
首先對于wi-fi調(diào)起后將在/sys/class/net目錄下創(chuàng)建相關(guān)的文件,如下所示:
- /sys/class/net # ls
- lo
- eth0
- wlan0
- /sys/class/net # ls -l
- lrwxrwxrwx root root 1969-12-31 16:59 lo -> ../../devices/virtual/net/lo
- lrwxrwxrwx root root 1969-12-31 16:00 eth0 -> ../../devices/platform/bcmgenet.0/net/eth0
- lrwxrwxrwx root root 1969-12-31 16:59 wlan0 -> ../../devices/platform/ehci-brcm.1/usb2/2-1/net/wlan0
通過在硬件抽象層添加下面的函數(shù),來確認(rèn)wi-fi是否連接?如下圖:
- static const char DRIVER_FILE[] = "/sys/class/net/wlan0";
- int check_device(){
- int devfd = 0;
- devfd = open(DRIVER_FILE, O_RDONLY);
- if (devfd < 0) {
- close(devfd);
- LOGE("Cannot open \"%s\": %s", DRIVER_FILE, strerror(errno));
- return -1;
- }
- close(devfd);
- return 0;
- }
下面通過jni將此函數(shù)傳遞給java層調(diào)用,來不斷的確認(rèn)wi-fi是否已經(jīng)連接!同時我在此處又增加了查看usb總線上設(shè)備的product、manu、idProduct、idVendor等來再次確認(rèn)wi-fi設(shè)備已經(jīng)連接,這個函數(shù)不再貼出,要求也很簡單,只需要讀/sys/class/目錄下usb的相關(guān)內(nèi)容即可!
老外寫的文檔,相當(dāng)有參考價值!
一、Contents
0. Understand how Android WiFi works.
1. Enable building of wpa_supplicant in your BoardConfig.mk
2. (Optional) Enable debug for wpa_supplicant.
3. Provide a proper wpa_supplicant.conf for your device
4. Have the correct paths and permissions created from init.rc
5. Make sure your wpa_supplicant and dhcpcd (optional) are starting from init.rc
6. Provide your driver either as a module or built in kernel and proper kernel support for it and modify Android source code accordingly.
7. Provide a firmware if your module needs it.
8. Make your driver work with Android custom wpa_supplicant commands and SIOCSIWPRIV ioctl
二、details
0. Understand how Android WiFi works.
Android uses a modified wpa_supplicant (external/wpa_supplicant) daemon for wifi support which is controlled through a socket by hardware/libhardware_legacy/wifi/wifi.c (WiFiHW) that gets controlled from Android UI through android.net.wifi package from frameworks/base/wifi/java/android/net/wifi/ and it's corresponding jni implementation in frameworks/base/core/jni/android_net_wifi_Wifi.cpp Higher level network management is done in frameworks/base/core/java/android/net
1. Enable building of wpa_supplicant in your BoardConfig.mk
This is by simply adding: BOARD_WPA_SUPPLICANT_DRIVER := WEXT
to your BoardConfig.mk. This will set WPA_BUILD_SUPPLICANT to true in
external/wpa_supplicant/Android.mk enabling building of driver_wext.c
If you have a custom wpa_supplicant driver (like madwifi or my custom android private commands emulation - see last paragraph) you can replace WEXT with AWEXT or your driver name (MADWIFI, PRISM etc).
2. (Optional) Enable debug for wpa_supplicant
By default wpa_supplicant is set to MSG_INFO that doesn't tell much. To enable more messages:
2.1 modify common.c and set wpa_debug_level = MSG_DEBUG
2.2 modify common.h and change #define wpa_printf from if ((level) >= MSG_INFO) to if ((level) >= MSG_DEBUG)
3. Provide a proper wpa_supplicant.conf for your device
Providing a wpa_supplicant.conf it's important because the control socket for android is specified in this file (ctrl_interface= ). This file should be copied by your AndroidBoard.mk to $(TARGET_OUT_ETC)/wifi (usually /system/etc/wifi/wpa_supplicant.conf). This location will be used on wpa_supplicant service from init.rc.
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.
Minimum required config options in wpa_supplicant.conf :
- Android private socket
ctrl_interface=wlan0
update_config=1
- Unix standard socket
ctrl_interface=DIR=/data/system/wpa_supplicant GROUP=wifi
update_config=1
Depending on your driver you might also want to add:
ap_scan=1
If you have AP association problems with should change to ap_scan=0 to let the driver do the association instead of wpa_supplicant.
If you want to let wpa_supplicant connect to non-WPA or open wireless networks (by default it skips these kind) add:
network={
key_mgmt=NONE / WPA-PSK
ssid=name
psk=password
priority=number
}
4. Have the correct permissions and paths created from init.rc
Incorrect permisions will result in wpa_supplicant not being able to create/open the control socket and libhardware_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. If your system has /system as read-only use a location like /data/misc/wifi/wpa_supplicant.conf and modify wpa_supplicant service in init.rc with new location.
Make sure the paths are correctly created in init.rc:
mkdir /system/etc/wifi 0770 wifi wifi
chmod 0770 /system/etc/wifi
chmod 0660 /system/etc/wifi/wpa_supplicant.conf
chown wifi wifi /system/etc/wifi/wpa_supplicant.conf
#wpa_supplicant control socket for android wifi.c (android private socket)
mkdir /data/misc/wifi 0770 wifi wifi
mkdir /data/misc/wifi/sockets 0770 wifi wifi
chmod 0770 /data/misc/wifi
chmod 0660 /data/misc/wifi/wpa_supplicant.conf
chown wifi wifi /data/misc/wifi
chown wifi wifi /data/misc/wifi/wpa_supplicant.conf
If you use a Unix standard socket in wpa_supplicant.conf (see above) add:
# wpa_supplicant socket (unix socket mode)
mkdir /data/system/wpa_supplicant 0771 wifi wifi
chmod 0771 /data/system/wpa_supplicant
chown wifi wifi /data/system/wpa_supplicant
Do not add these if you use Android private socket because it will make wpa_supplicant non-functional, because hardware/libhardware_legacy/wifi/wifi.c check for existence of the /data/system/wpa_supplicant folder and will pass a wrong interface name towpa_ctrl_open() function.
5. Make sure your wpa_supplicant and dhcpcd are starting from init.rc
For wpa_supplicant the init.rc startup like should be depending on which path you chosen:
- Android private socket:
service wpa_supplicant /system/bin/wpa_supplicant -dd -Dwext -iwlan0 -c /system/etc/wifi/wpa_supplicant.conf
socket wpa_wlan0 dgram 660 wifi wifi
group system wifi inet
disabled
oneshot
- Unix standard socket:
service wpa_supplicant /system/bin/wpa_supplicant -dd -Dwext -iwlan0 -c /system/etc/wifi/wpa_supplicant.conf
group system wifi inet
disabled
oneshot
If your wifi driver creates a wifi interface with other name than wlan0 you will have to modify the above line accordingly.
You also should have dhcpcd starting from init.rc
service dhcpcd /system/bin/dhcpcd wlan0
group system dhcp
disabled
oneshot
6. Provide your driver either as a module or built in kernel and proper kernel support for it
First make sure that CONFIG_PACKET and CONFIG_NET_RADIO (wireless extensions) are enabled in your kernel. The driver can be built as module (default android way) or built in kernel (if you want to rely in kernel auto probing to support multiple driver eg. USB wifi) but will require source code modifications (see below).
- As kernel module:
Define in your BoardConfig.mk:
1. WIFI_DRIVER_MODULE_PATH := path to the module to be loaded
You need to specify module name in that path too, usually should look something like /system/lib/modules/wlan.ko
2. WIFI_DRIVER_MODULE_NAME:= the name of the network interface that the driver creates, for example wlan0
3. WIFI_DRIVER_MODULE_ARG:= any arguments that you want to pass to the driver on insmod, for example nohwcrypt
Make sure you copy your kernel module when building android to the correct location.
- As built in kernel:
- First init.rc needs to be modified to inform hardware/libhardware_legacy/wifi/wifi.c about the name of the interface, that the driver is already loaded and set the status of wpa_supplicant to running:
setprop wifi.interface "wlan0"
setprop wlan.driver.status "ok"
Do NOT add setprop init.svc.wpa_supplicant "running" as I previously mentioned as it will prevent wpa_supplicant from starting from init.
- Secondly hardware/libhardware_legacy/wifi/wifi.c need to be modified so the functions insmod() and rmmod() return 0 (simply add return 0; as the first line in functions since they are not needed when driver is built in kernel) and return before checking for /proc/modules in check_driver_loaded() function.
You might encounter problems with WifiHW module not being able to connect to wpa_supplicant socket even with the correct permisions. Try to turn off / turn on Wifi from the GUI.
7. Provide a firmware if your driver needs it
If your driver needs a firmware you will have to copy this firmware file to /etc/firmware on your android build. Android doesn't use a standard hotplug binary (although there is an implementation available on android-x86 system/code/toolbox/hotplug.c) instead the init process takes care of firmware events and loads the firmware file from /etc/firmware (see: system/core/init/devices.c handle_firmware_event() function).
Firmware file name is defined by the driver and might also contain a folder like: RTL8192SU/rtl8192sfw.bin, entire file path should be available in/etc/firmware
8. Make your driver work with Android custom wpa_supplicant commands and SIOCSIWPRIV ioctl.
Android uses SIOCSIWPRIV ioctl to send commands to modify driver behaviour and receive information like signal strength, mac address of the AP, link speed etc. This ioctl is usually not implemented in any known wireless drivers except bcm4329 which is in google msm kernel branch.
The errors from not having this ioctl implemented will look like:
E/wpa_supplicant( ): wpa_driver_priv_driver_cmd failed wpa_driver_priv_driver_cmd RSSI len = 4096
E/wpa_supplicant( ): wpa_driver_priv_driver_cmd failed
D/wpa_supplicant( ): wpa_driver_priv_driver_cmd LINKSPEED len = 4096
E/wpa_supplicant( ): wpa_driver_priv_driver_cmd failed
I/wpa_supplicant( ): CTRL-EVENT-DRIVER-STATE HANGED
After 4, WEXT_NUMBER_SEQUENTIAL_ERRORS errors, android will abort using the device.
To quickly test your wifi from interface you can disable error checking in external/wpa_supplicant/driver_wext.c by simply making ret = 0; inwpa_driver_priv_driver_cmd() function after the SIOCSIWPRIV ioctl call. This will make all access points in android UI appear without signal or MAC address.
To proper implement the ioctl you will need to modify your kernel driver to reply to SIOCSIWPRIV ioctl with RSSI (signal strength) and MACADDR commands being the most important.
A better way is to add a custom driver_xxx.c to google external/wpa_supplicant/ implementing wpa_driver_priv_driver_cmd() function that will take care of RSSI, MACADDR and others, through calls to SIOCGIWSTATS, SIOCGIFHWADDR ioctls, with the rest of the functions being called from driver_wext.c.
Below is a link to a patch for wpa_supplicant that I did for mini-box.com picoPC Android build. It creates a new driver awext which "emulates" android driver commands using wireless extensions ioctls.