android wifi ralink rt3070开发记录

一、wifi基本架构

    1、开源代码移植部分(external目录下)
        wireless_tools、wpa_supplicant、wpa_supplicant_6(后两项已经移植过)
        生成库libwpaclient.so和守护进程wpa_supplicant及iwconfig、iwlist等相关的测试程序
    2、hardware/libhardware_legary/wifi/wifi.c是wifi管理库
        生成libnetutils.so
        同时会和wpa_supplicant守护进程通信
    3、JNI部分
        frameworks/base/core/jni/android_net_wifi_Wifi.cpp  这个是无线connect、scan方面的调用
        frameworks/base/core/jni/android_net_NetUtils.cpp   这个是管理网络方面的工具,如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         这个是管理网络的工具,调用第三条的第二个jni
    5、WIFI Settings位于
        packages/apps/Settings/src/com/android/settings/wifi/
    6、WIFI驱动模块 rt5370sta.ko(此驱动兼容使用ralink的好多种设备驱动,具体可以查看USB_DEVICE_ID)
        wpa_supplicant通过wireless_ext 接口和驱动通信
    7、WIFI 硬件模块
        D-Link DWA-125 芯片:ralink RT3070
二、wifi开发记录
        1、5370驱动编译安装及使用过程
              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 内容:
                    ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
                    network={
                            ssid="home"
                            scan_ssid=1
                            key_mgmt=WPA-PSK
                            psk="very secret passphrase"
                   } // 这个地方的大括号中的内容可在settings中点击选择某个ap后自动生成
              #sudo su   (android平台需要自己添加脚本编译,和这里写的有差异)
                   #make clean
                   #make
                   #make install
                   #modprobe rt5370sta
                   #ifconfig wlan0 up
                   #iwconfig wlan0
                   #iwlist wlan0 scan 这时候已经可以扫描wi-fi网络了
                   下面是dhcpcd wlan0即可。
        2、几个可执行程序:wpa_supplicant,wpa_cli等。wpa_supplicant是核心程序,它和wpa_cli的关系就是服务和客户端的关系:后台运行wpa_supplicant,可以使用wpa_cli来搜索、设置、和连接网络等,这两个可执行程序很重要
           在android中主要是Settings这个属于system的进程调用的libhardware_legecy库中的wifi.c文件和wpa_supplicant通信,同时也调用了wpa_supplicant中提供的libwpa_client.so库,这两个进程间通过socket通信收发数据来得到当前状态,同时也是通过wifi.c来启动和停止init.rc中的wpa_supplicant进程。
           dhcpcd用来自动获取ip。
           iwconfig  iw event   iwgetid   iwlist    iwpriv    iwspy这几个是测试命令,可用来测试wifi当前的情况,以及scan ap等。
      3、以上是命令测试过程,下面进行代码的修改部分说明(broadcom BCM7231)
            wpa_supplicant 和wpa_cli原生android2.3已经移植,但是没有wireless tool工具,需要将工具移植进来,
不过这些工具相对都比较容易移植,不再详述,下载源码位置如下
http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html。

     然后从驱动开始修改起
               1)修改5370驱动
                      设备名include/rtmp_def.h 修改两个宏定义从ra0修改为wlan0;
                      LINUX_SRC=... (android的kernel位置)             

                      ifeq($(PLATFORM),BCM7431)

                      LINUX_SRC= ${ANDROID_PATH}/kernel   #修改path为你的android目录

                      endif

                             驱动编译后会生成两个文件:RT5370STA.ko  和RT2870STA.dat,后面

                      会看到需要拷贝这两个文件到系统中。

                            ioctl 驱动代码接口在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与下层驱动通讯时出现ioctl[SIOCSIWPRIV]错误,因为现在大部分wifi模块对SIOCSIWPRIV命令不处理,而这个命令要用于侦测wifi强度RSSI的,比较简单的方法是在wifi驱动中增加个空函数或者修改调用的返回值为0。由于大多数模块不支持SIOCSIWPRIV,所以目前采用修改调用的返回值的方法。修改:froyo\external\wpa_supplicant\driver_wext.c

               wpa_driver_priv_driver_cmd()函数中:

                   // if((ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr)) < 0) {

                            //perror("ioctl[SIOCSIWPRIV]");

                      //                   }     

// 如果这里不注释掉,将导致系统不断报错,错误为 IOCTL::unknownIOCTL's cmd = 0x00008b0c,我跟踪了下代码驱动中并没有这个ioctl,

另外在wpa_supplicant的头文件中也显示未使用,但是在代码中却用了这个ioctl,所以必须把这段代码删除!


           6) 修改android打开WIFI流程

               经测试5370模块在ifconfig wlan0 down时配置

               iwconfig wlan0 mode Managed会出错,Android代码中的配置过程也是这样,表现就是关闭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);
                            }    //此处若不修改将导致wifi关闭后再次开启,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代码的调用函数为:

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函数又调用了ifc_disable函数,如下:

int ifc_disable(const char *ifname)
{
    int result;

    ifc_init();  // 调用socket函数,得到fd
    result = ifc_down(ifname);  // 通过ioctl设定到内核
    ifc_set_addr(ifname, 0);
    ifc_close(); // 关闭fd
    return result;
}
ifc_down函数

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 设定到kernel。

             7) 创建wpa_supplicant.conf文件

                     在你的board配置目录下MIPSAndroid_Phase2.1/bcm_mipsgingerbread20111129/AppLibs/opensource/android/src/mips-gingerbread/vendor/broadcom/bcm_platform/prebuilt创建一个wpa_supplicant.conf文件,输入如下内容:

                        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 然后

                 根据您的脚本build android or all


 三、开发遇到的问题汇总
    1、如果发现wifi当前是开着的,而却发现关机再重启却没自动开启的话,很有可能是飞行模式揉的货! 修改数据库即可正常 ,如下:
sqlite3 /data/data/com.android.providers.settings/databases/settings.db
delete from system where name = 'airplane_mode_on';
.exit

     2、wi-fi信号强度问题
        源码位置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);
            }
        }
    } 
    /**
     * 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;
        }
    }
 
   

I/WifiStateTracker( 1799): ----------getRssiApprox------------WifiNative.getRssiCommand():-20
I/WifiStateTracker( 1799): ---------------------->newRssi:-20
I/WifiStateTracker( 1799): ---------------------->newSignalLevel:3

        根据log可发现level为-20,而根据计算公式算为 (-55 - (-100))/ 3 = 15;
若rssi level = -20,那么结果为 (-20 - (-100))/ 15 = 5。
后来发现自己忽略了前面一个if语句,-20 明显 > -55,将不进入计算分支,而直接计算 4 - 1 = 3;
所以问题就解决了!


        3、usb类型的wi-fi设备插拔导致的界面死掉的问题解决方案
      首先对于wi-fi调起后将在/sys/class/net目录下创建相关的文件,如下所示:
/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
    通过在硬件抽象层添加下面的函数,来确认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将此函数传递给java层调用,来不断的确认wi-fi是否已经连接!同时我在此处又增加了查看usb总线上设备的product、manu、idProduct、idVendor等来再次确认wi-fi设备已经连接,这个函数不再贴出,要求也很简单,只需要读/sys/class/目录下usb的相关内容即可!

老外写的文档,相当有参考价值!
一、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.

你可能感兴趣的:(android wifi ralink rt3070开发记录)