android之wifi移植全过程

来源:互联网 发布:淘宝达人一个月多少钱 编辑:程序博客网 时间:2024/06/09 20:57
硬件环境     
     WIFI模块:Marvell8686 SDIO WIFI
     开发板:S5PC100     
     软件环境: Linux 2.6.29  Android 2.1

项目目标:实现WIFI上网功能、并对WIFI休眠进行改善。
项目开发流程:
硬件分析:对Marvell8686 SDIO WIFI模块硬件工作特性了解和分析
工作原理分析:对Marvel8686 SDIO WIFI工作原理进行分析
Android WIFI框架分析:对Android WIFI系统框架分析
进行源码分析、编写、修改及编译
调试、并完善

一、1.编译内核,生成驱动模块
     在内核的根目录下执行make
     生成libertas.ko 和libertas_sdio.ko
     [*] Networking support  --->  
         [*]   Wireless  --->  
                 --- Wireless                                                
                <*>   Improved wireless configuration API                   
                 [*]     cfg80211 regulatory debugging                        
                 [*]     nl80211 new netlink interface support                                                                              
                 -*-   Common routines for IEEE802.11 drivers    
         Device Drivers  --->   
         [*] Network device support  --->  
                Wireless LAN  --->   
               <*>   Marvell 8xxx Libertas WLAN driver support              (注:编译进内核,若模块则是:libertas.ko)       
               <M>     Marvell Libertas 8385 and 8686 SDIO 802.11b/g cards  (注:编译成libertas_sdio.ko)
     
     2.编译内核,确保支持sd卡
        Device Drivers  ---
           <*> MMC/SD/SDIO card support  ---> 
             --- MMC/SD/SDIO card support                                     
             [*]   MMC debugging                                              
             [ ]   Allow unsafe resume (DANGEROUS)                            
             [*]   MMC embedded SDIO device support (EXPERIMENTAL)            
             [ ]   Enable paranoid SD card initialization (EXPERIMENTAL)      
                   *** MMC/SD/SDIO Card Drivers ***                           
             <*>   MMC block device driver                                    
             [*]     Use bounce buffer for simple hosts                       
             [ ]     Deferr MMC layer resume until I/O is requested           
             < >   SDIO UART/GPS class support                               
             < >   MMC host test driver                                        
                   *** MMC/SD/SDIO Host Controller Drivers ***                
             <*>   Secure Digital Host  
       3.make zImage
         make modules
        (libertas_sdio.ko在drivers/net/wireless/libertas目录下)
二、制作测试工具(使用静态编译) 
    现在,sd卡支持了,驱动以内核自带的以模块的方式编译得到。
    接下来先编译几个测试工具。
    测试无线网卡用无线工具iwconfig iwlist等命令是通过开源软件wireless_tools_29.rar编译得到。         
    步骤:
    1.解压。由于这的是win32的压缩包,先在windows底下解压,再拷贝到Ubuntu下。
    2.修改Makefile:
           8   PREFIX = ./tools  //指定安装路径                   
           12  CC = arm-linux-gnu-gcc (和编译你的文件系统所用保持一致,需要注意的是,如果在执行sudo make 就要该编译链的绝对路径)                                                                                                      
           14  AR = arm-linux-gnu-ar   
           
           #BUILD_STATIC = y          -->    BUILD_STATIC = y                                       
           #BUILD_STRIPPING = y       -->    BUILD_STRIPPING = y   
           
 
           CFLAGS=-Os -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wshadow \         
                 -Wpointer-arith -Wcast-qual -Winline -I. 
           在这后面添加新行:                              
           CFLAGS += -static 
           
    3.make
    4.make install
      由于我是在当前目录下(PREFIX = ./tools) 产生的这个tools文件夹,
      查看有:
      lib sbin usr
      lib目录,libiw.a静态库 ;而sbin目录为一些网络工具,如:iwlist、iwconfig等
      到里面的sbin目录底下,
      $file iwlist  输出信息:iwlist: ELF 32-bit LSB executable, ARM, version 1, statically linked, for GNU/Linux 2.4.3, strippe
      确保是静态的。 
      
      然后将这些命令复制到android文件系统的/system/busybox/bin(就是out/target/prodruct/fs100/system/busybox/bin)
      或者system/bin(就是out/target/prodruct/fs100/system/bin)目录下就可以使用这些命令了。  
 
 三、将固件放到指定目录下。
     1.mkdir /system/etc/firmware(就是out/target/prodruct/fs100/system/etc/firmware)
     2.cp sd8686.bin sd8686_helper.bin  out/target/prodruct/fs100/system/etc/firmware
 
 四、测试,sdio卡是否可用。
     如果已经编译好了文件系统,就可以跳过第一步。
     1.编译android系统。
               1)在文件系统根目录下执行:
               liyulei@liyulei:~/anrdoid/fs/android_system$ . ./build/envsetup.sh
             注意这里两个’.’  之间有一个空格,第一个’.’指定用当前 shell 解析这个脚本,否则不能执行。
            2)配置板级信息:
            liyulei@liyulei:~/anrdoid/fs/android_system$ tapas
            就是上一步执行结束之后导出到环境变量里的命令,专门用来配置板级信息的。
             Build for the simulator or the device? 
                    1. Device 
                   2. Simulator 
            Which would you like? [1] 1 
            Build type choices are: 
                   1. release 
                   2. debug 
            Which would you like? [1] 1 
            Which product would you like? [fs100] fs100 
            Variant choices are: 
                   1. user 
                   2. userdebug 
                   3. eng 
            Which would you like? [eng] eng 
            
            确保输出的配置信息为:
            PLATFORM_VERSION_CODENAME=REL 
            PLATFORM_VERSION=2.1-update1  
            TARGET_PRODUCT=fs_s5pc100     
            TARGET_BUILD_VARIANT=eng      
            TARGET_SIMULATOR=false        
            TARGET_BUILD_TYPE=release     
            TARGET_ARCH=arm               
            HOST_ARCH=x86                 
            HOST_OS=linux                 
            HOST_BUILD_TYPE=release       
            BUILD_ID= ERE27               
            
            3)开始编译(如果不能找到 mm,执行”source build/envsetup.sh”): 
            liyulei@liyulei:~/anrdoid/fs/android_system$ mm
    
   2.重新生成文件系统镜像。
     liyulei@liyulei:~/anrdoid/fs/android_system$ ./make_fs100_yaffs2_image.sh
     就会在 Android 源码根目录下生成目录“fs100_root”,这个目录就是编译生成的 Android 文件系统,  
     调试时可以直接把这个目录作为 NFS-Server 的目录。还会生成一个“fs100_root.img”文件,这个文件就
     是 Android的 yaffs2 格式的镜像,可以烧写到 Nand Flash 上。
       这里我是烧写上fs100_root.img.
     
     3.手动加载驱动。
       由于sdio8686。需要加载两个.ko(libertas.ko、libertas_sdio.ko) 文件。
       上面linertas.ko的模块,我已经编进内核。
       所以我只需执行:
       1)/# insmod libertas_sdio.ko   
       输出信息:
       libertas_sdio: Libertas SDIO driver                                 
     libertas_sdio: Copyright Pierre Ossman                              
     __func__ = if_sdio_prog_helper                                      
     libertas_sdio mmc1:0001:1: firmware: requesting sd8686_helper.bin   
     init: untracked pid 2137 exited                                     
     libertas_sdio mmc1:0001:1: firmware: requesting sd8686.bin          
     init: untracked pid 2140 exited                                     
     libertas: 00:0b:6c:91:a3:f6, fw 9.70.3p24, cap 0x00000303           
     libertas: unidentified region code; using the default (USA)         
     wlan0 (libertas_sdio): not using net_device_ops yet                 
     libertas: PREP_CMD: command 0x00a3 failed: 2                        
     libertas: PREP_CMD: command 0x00a3 failed: 2                        
     libertas: wlan0: Marvell WLAN 802.11 adapter                        
    2)/# ifconfig -a  
       (要是提示:-a: No such device,则输入命令:system/busybox/sbin/ifconfig -a)    
    查看是否检测到无线网卡                           
           有如下信息说明检测到无线网卡                                    
             wlan0     Link encap:Ethernet  HWaddr 00:0B:6C:91:A3:F6       
                       BROADCAST MULTICAST  MTU:1500  Metric:1             
                       RX packets:0 errors:0 dropped:0 overruns:0 frame:0  
                       TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
                       collisions:0 txqueuelen:1000                        
                       RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)              
    3)测试:  
         /#ifconfig wlan0 up                                                                                                          
        /#iwlist wlan0 scanning                                                                                                         
        /#iwconfig wlan0 essid "fs100"                                                                                                  
        /#ifconfig wlan0 192.168.1.99 netmask 255.255.255.0 up (静态分配ip,
         也可以动态分配,用DHCP)
         /#route add default gw 192.168.1.1(无线路由)
         /#ping 192.168.1.1            
    4)能够ping通后,说明sdio8686 wifi网卡没有问题
    
五、测试wpa_supplicant。
  因为现在的无线wifi网络大多是wpa加密。 所以需要用到wpa_supplicant。
    android系统中也自带有wpa_supplicant。
    wifi的大致架构是这样的,app-->java framework-->|jni|-->c++ framework -->wifi.c -->wpa_supplicant-->sdio8686.
    所以我们要先测试低层先通了,因此,就得先测试确保wpa_supplicant和sdio8686通了的。
    我们编译android系统时,就已经把自带的wpa_supplicant和wpa_cli编译好并放到system/bin目录下了. 
    1.配置wpa_supplicant。
    在liyulei@liyulei:~/anrdoid/fs/android_system/external/wpa_supplicant/在目录下有个wpa_supplicant.conf。
    将wpa_supplicant.conf放到out/target/product/fs100/system/etc 目录下。如果是烧到板子上的话,需要重烧板子。
    要是以网络挂载的方式,则放到相应的目录。
    #vim /rootfs/filesystem/etc/wpa_supplicant.conf           
                                                              
    修改内容如下:                                            
                                                              
    # WPA-PSK/TKIP                                            
                                                              
     ctrl_interface=/var/run/wpa_supplicant                    
                                                              
     network={                                                 
                     ssid="fs100"     //填写无线网络的的用户名
                      key_mgmt=WPA-PSK                          
                      proto=WPA                                 
                     pairwise=TKIP                             
                     group=TKIP                                
                     psk="1234567890" //填写密码               
     }                                                         
    
    2.#mkdir –p /var/run/wpa_supplicant
    3.确认是否加载驱动。
     用ifconfig -a查看是否已经创建wlan0这个节点。
      没有就把驱动加载进内核。
    4.创建连接暗文密码(PSK密码),通过明码转换                                                                    
      #cd /etc (该目录下要有wpa_supplicant.conf)                                                                                                  
      #wpa_passphrase fs100 1234567890 >> wpa_supplicant.conf                                                   
      此时将在wpa_supplicant.conf文件中生成:                                                                    
      network={                                                                                                  
            ssid="fs100"                                                                                        
            #psk="1234567890" //此物为路由器中设定的人类能读得懂的密码,供我们使用                               
            psk=d290464a66df8541cee4f100627446177ee7ce5d9eb36981e4dff412730b2d5a //这个又1234567890转换后的psk密码
      }                                                                                                          
       -----------------------------------------------------------------------------------------------------<----
       ---->遇到问题:在测试过程中要用到wpa_passphrase这个命令程序。但是android并没提供wpa_passphrase       <----
       ---->这命令,我只通过wpa_supplicant-0.7.3这个源码包编译出这个命令。但是这个命令在开发板上执行        <----
       ---->不了(编译链不对)。我又找到android源码中有wpa_passphrase.c,而编译出来的路径下通过find         <----
       ---->命令去找这个wpa_passphrase又找不到。                                                            <----
       ---->解决办法:同过分析wpa_passphrase.c才发现,里面就短短的一个mian函数。有个提示                    <----
       ---->usage: wpa_passphrase <ssid> [passphrase]\n""\nIf passphrase is left out, it will be read from "<----
     ---->"stdin\n                                                                                        <----
       ---->现在不用我说都知道了吧!所以这个在哪运行都可以,这命令就是为了通过ssid和passphrase得到暗文。    <----
       ---->所以我在Ubuntu底下直接执行:wpa_passphrase fs100 1234567890                                     <----
       ---->同样输出信息:network={                                                                         <----                             
       ---->                          ssid="fs100"                                                          <----                             
       ---->                          #psk="1234567890"                                                     <----
       ---->                          psk=d290464a66df8541cee4f100627446177ee7ce5d9eb36981e4dff412730b2d5a  <----
       ---->                    }                                                                           <----                             
       -----------------------------------------------------------------------------------------------------<----- 
     5.然后修改wpa_supplicant.conf配置文件,把 psk="1234567890" 这一行明文密码改成生成的暗文密码,即:
               psk=d290464a66df8541cee4f100627446177ee7ce5d9eb36981e4dff412730b2d5a                  
                                                                                                     
       其它生成的多余信息删除,最后wpa_supplicant.conf文件如下:                                     
       # WPA-PSK/TKIP                                                                                
                                                                                              
       ctrl_interface=/var/run/wpa_supplicant                                                        
                                                                                              
       network={                                                                                     
                  ssid="FS2410"     //填写无线网络的的用户名                                         
                  key_mgmt=WPA-PSK                                                                   
                  proto=WPA                                                                          
                  pairwise=TKIP                                                                      
                  group=TKIP                                                                         
                 psk=d290464a66df8541cee4f100627446177ee7ce5d9eb36981e4dff412730b2d5a               
       } 
       
     6.链接AP:
             在开发板终端输入wpa_supplicant回车,会显示帮助信息,最后有个:                         
             example:                                                                             
                   wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant.conf                       
             拷贝example用法,执行:                                                              
             # wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant.conf &(需要一直放在后台运行)   
             打印信息有:                                                                         
             Trying to associate with 00:26:f2:0d:5a:c4 (SSID='fs100' freq=2412 MHz)             
             Associated with 00:23:68:28:4e:a8                                                    
             CTRL-EVENT-DISCONNECTED bssid=00:23:68:28:4e:a8 reason=0                             
             Associated with 00:26:f2:0d:5a:c4                                                    
             WPA: Key negotiation completed with 00:26:f2:0d:5a:c4 [PTK=TKIP GTK=TKIP]            
             CTRL-EVENT-CONNECTED - Connection to 00:26:f2:0d:5a:c4 completed (auth) [id=0 id_str=]
                                                                                           
             分配IP地址:                                                                         
             #ifconfig wlan0 192.168.1.5  //也可以动态分配 dhclient wlan0                         
             再ping下网关,是否连接成功:                                                         
             #ping 192.168.1.1                                                                    
                                                                                            
             3 packets transmitted, 3 packets received, 0% packet loss                            
             round-trip min/avg/max = 17.627/20.023/24.631 ms                                     
             ……                                                                                 
                                                                                            
             无线网卡连接成功!      
         

六、android的wifi移植。
     现在底层的都通了,接下来就把wifi移植到android系统中。
     1.提供固件firmware给驱动。
        WIFI需要的firmware要复制到/etc/firmware。   或者复制到WIFI驱动指定的位置,然后WIFI驱动会自动加载。
        在此把wifi模块提供的sd8686.bin sd8686_helper.bin放到out/target/product/fs100/system/etc/firmware目录下。
        其实,和上面放目录是一样的。
     
     2.修改自己定制的BoardConfig.mk,使能wpa_supplicant。
       修改vendor/farsight/fs100/BoardConfig.mk:                                                       
          把BOARD_WPA_SUPPLICANT_DRIVER :=true                                                          
          改为BOARD_WPA_SUPPLICANT_DRIVER := WEXT                                                                                                                                                
          目的是:把driver_wext.c作为wpa_supplicant的driver。wpa_supplicant通过它去与内核的wifi驱动打交道。
       修改external/wpa_supplicant/Android.mk                                                           
           把WPA_BUILD_SUPPLICANT :=false                                                               
           改为WPA_BUILD_SUPPLICANT := true                                                         
          默认使用驱动driver_wext.c。                                                                   
          如果使用定制的wpa_supplicant驱动(例如 madwifi),可以设置:                                     
          BOARD_WPA_SUPPLICANT_DRIVER := MADWIFI 
           
                                                                   
      3.使wpa_supplicant打印更多的调试信息
    wpa_supplicant默认信息显示的等级为SG_INFO,为了输出更多信息,可修改:  
        修改external/wpa_supplicant/common.c                                   
            把int wpa_debug_level = MSG_INFO;                                  
            改为:int wpa_debug_level = MSG_DEBUG;                             
        修改external/wpa_supplicant/common.h                                   
            把宏定义#define wpa_printf(level, ...)中的if ((level) >= MSG_INFO) 
            改为if ((level) >= MSG_DEBUG) 
      4.提供一个合适的wpa_supplicant.conf 
        修改wpa_supplicant.conf:                                                                                                                 
           把external/wpa_supplicant/wpa_supplicant.conf拷贝到out/target/product/fs100/system/etc/wifi/目录下,
           并把:ctrl_interface=DIR=/data/misc/wifi/wpa_supplicant GROUP=wifi                                 
           改为:                                                                                             
           ctrl_interface=wlan0                                                                               
      5.修改init.rc配置路径和权限
        A)配置init.rc文件修改out/target/product/fs100/root/init.rc, 让wifi用户拥有相关的权限, 
          在 #give system access to wpa_supplicant.conf for backup and restore后面增加:
             #add by liyulei 2011-11-19                                                                                                                       
             mkdir /data/misc/wifi/sockets 0777 wifi wifi                                                                                                           
        chown wifi wifi /data/misc/wifi                                                                                                                   
             chown wifi wifi /data/misc/wifi/wpa_supplicant.conf                                                                                                           
             #for dhcp                                                                                                                                      
             mkdir /data/misc/dhcp 0777 dhcp dhcp                                                                                                    
             chmod 0770 /data/misc/dhcp                                                                                                             
             #end add                                                                                                                                                      
        B)注释原有环境变量#export PATH 
          改为:                                                                                                                             
         export PATH /sbin:/system/sbin:/system/bin:/system/xbin                                                                                       
          #above modified by liyulei 2011-11-19                                                                                                                            
      6. 确保wpa_supplicant和dhcpcd是通过init.c起来的。
         配置init.rc文件修改out/target/product/fs100/root/init.rc, 在末尾添加:                                       
             #add by liyulei 2011-11-19
             for wifi 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                                                                
             #for dhcp                                                                          
             service dhcpcd /system/bin/dhcpcd wlan0                                          
                     group system dhcp                                                           
                     disabled                                                                           
                     oneshot                                                                       
             #end add。                                                                                                
   7.设置驱动以模块方式加载
   拷贝内核生成的drivers/net/wireless/libertas/libertas_sdio驱动模块
   到out/target/product/fs100/system/lib/modules/目录下。
   然后修改hardware/libhardware_legacy/wifi/wifi.c                                                                       
          1)修改wifi.c中的宏:
             #define WIFI_DRIVER_MODULE_PATH            "/system/lib/modules/libertas_sdio.ko"                                                            
             #define WIFI_DRIVER_MODULE_NAME            "libertas_sdio"                                                                                       
             #define WIFI_TEST_INTERFACE              "wlan0"  
          或者,也可以这样改:
            修改vendor/farsight/fs100/BoardConfig.mk:
              WIFI_DRIVER_MODULE_PATH  ="/system/lib/modules/libertas_sdio.ko"                                                            
              WIFI_DRIVER_MODULE_NAME  ="libertas_sdio"                                                                                       
              WIFI_TEST_INTERFACE     ="wlan0"  
            和上面一样的效果。
                                                                                                           
      8.添加休眠唤醒代码:
      1)在frameworks\base\core\Jni\android_net_wifi_Wifi.cpp中添加相应的休眠唤醒函数:
      在static JNINativeMethod gWifiMethods[]结构体添加方法: 
      {"moduleWakeupStatus","()Z",(void*)android_net_wifi_moduleWakeupStatus},
      {"WaitTime","(I)Z",(void*)android_net_wifi_WaitTime}, 
      并实现这些方法/*add by liyulei 2011-11-20*/                                                      
          static jboolean android_net_wifi_moduleWakeupStatus(JNIEnv* env, jobject clazz)  
        {                                                                                  
         return (jboolean)(::wifi_module_wakeup_status() == 0);                            
        }                                                                                  
        static jboolean android_net_wifi_WaitTime(JNIEnv* env, jobject clazz, jint waittime)
        {                                                                                  
         return (jboolean)(::wifi_module_wait_time(waittime) == 0);                       
        }                                                                                  
        /*end add by liyulei*/  
        
        2)而相应的细体实现在wifi.c中:
         在wifi.c添加:                                                            
           /*add by caoyi 2011-10-20*/               
           int wifi_module_wakeup_status()           
              {                                      
                    return 1;                        
              }                                      
              int wifi_module_wait_time(int watiTime)     
             {                                            
                sleep(watiTime);                         
                   return  0;                                                                                                                                                    
              }                                      
           /*end add*/                               
      
      9.配置dhcpcd.conf
        修改源码目录下external/dhcpcd下的Android.mk文件
    取消注释
       -->26  include $(CLEAR_VARS)
       -->27 LOCAL_MODULE := dhcpcd.conf
       -->28 LOCAL_MODULE_TAGS := user
       -->29 LOCAL_MODULE_CLASS := ETC
       -->30 LOCAL_MODULE_PATH := $(etc_dir)
       -->31 LOCAL_SRC_FILES := android.conf
       -->32 include $(BUILD_PREBUILT)   
       然后重新编译mm,将编译产生的dhcpcd.conf放置到文件系统的目录system/etc/dhcpcd/dhcpcd.conf
        最后确定dhcpcd.conf内容有:
       interface wlan0
       option subnet_mask, routers, domain_name_servers 
       option ntp_servers  
       没有的话,就修改。
          
      10.修改WifiStateTracker.java
       将frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java 里的mInterfaceName = SystemProperties.get("wifi.interface", "eth0");
       改为:
       mInterfaceName = SystemProperties.get("wifi.interface", "wlan0");
       最后重新编译mm
       编译镜像文件后烧写到开发板上就可以使用WiFi模块连接网络。
 
                                   

转载地址:http://blog.csdn.net/liyulei316686082/article/details/7006577
原创粉丝点击