zoukankan      html  css  js  c++  java
  • Android Wifi BT的工作流程和porting(精)


    Wifi 网卡状态

    1.    WIFI_STATE_DISABLED: WIFI网卡不可用

    2.    WIFI_STATE_DISABLING: WIFI正在关闭

    3.    WIFI_STATE_ENABLED:WIFI网卡可用

    4.    WIFI_STATE_ENABLING:WIFI网卡正在打开

    5.    WIFI_STATE_UNKNOWN:未知网卡状态

    WIFI 访问网络需要的权限

    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE">

    </uses-permission>修改网络状态的权限

    <uses-permission

    android:name="android.permission.CHANGE_WIFI_STATE">

    </uses-permission>修改WIFI状态的权限

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">

    </uses-permission>访问网络权限

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE">

    </uses-permission>访问WIFI权限

    WIFI 核心模块

    n  WifiService

    由SystemServer启动的时候生成的ConnecttivityService创建,负责启动关闭wpa_supplicant,启动和关闭WifiMonitor线程,把命令下发给wpa_supplicant以及跟新WIFI的状态

    n  WifiMonitor

      负责从wpa_supplicant接收事件通知

    n  Wpa_supplicant

    1、读取配置文件

    2、初始化配置参数,驱动函数

    3、让驱动scan当前所有的bssid

    4、检查扫描的参数是否和用户设置的想否

    5、如果相符,通知驱动进行权限 认证操作

    6、连上AP

    n  Wifi驱动模块

    厂商提供的source,主要进行load firmware和kernel的wireless进行通信

    n  Wifi电源管理模块

    主要控制硬件的GPIO和上下电,让CPU和Wifi模组之间通过sdio接口通信

    Wifi工作步骤

    n  Wifi模块初期化

    n  Wifi启动

    n  查找热点(AP)

    n  配置AP

    n  配置AP参数

    n  Wifi连接

    n  IP地址配置

    Wifi模块代码总结

    n  Wifi Application代码

    packages/apps/Settings/src/com/android/settings/wifi

    n  Wifi Framework

    frameworks/base/wifi/java/android/net/wifi

    frameworks/base/services/java/com/android/server

    n  Wifi JNI

    frameworks/base/core/jni/android_net_wifi_Wifi.cpp

    n  Wifi Hardware

    hardware/libhardware_legacy/wifi/wifi.c

    n  Wifi tool

    external/wpa_supplicant

    n  Wifi kernel

    net/wireless     drivers/wlan_sd8688       arch/arm/mach-pxa/wlan_pm.c

    Wifi模块的初始化:

    在 SystemServer 启动的时候,会生成一个ConnectivityService 的实例, ConnectivityService 的构造函数会创建WifiService,WifiStateTracker 会创建WifiMonitor 接收来自底层的事件,WifiService 和WifiMonitor 是整个模块的核心。WifiService 负责启动关闭wpa_supplicant、启动关闭WifiMonitor 监视线程和把命令下发给wpa_supplicant,而WifiMonitor 则负责从wpa_supplicant 接收事件通知。

    Wifi模块的启动:

    WirelessSettings 在初始化的时候配置了由WifiEnabler 来处理Wifi 按钮,

    当用户按下Wifi 按钮后,Android 会调用WifiEnabler 的onPreferenceChange,再由WifiEnabler调用WifiManager 的setWifiEnabled 接口函数,通过AIDL,实际调用的是WifiService 的setWifiEnabled 函数,WifiService 接着向自身发送一条MESSAGE_ENABLE_WIFI 消息,在处理该消息的代码中做真正的使能工作:首先装载WIFI 内核模块(该模块的位置硬编码为"/system/lib/modules/wlan.ko" ), 然后启动wpa_supplicant ( 配置文件硬编码为"/data/misc/wifi/wpa_supplicant.conf"),再通过WifiStateTracker 来启动WifiMonitor 中的监视线程。

    查找热点(AP):

    (Wifi开启)中讲到Wifi模块开启后会对外发送WIFI_STATE_CHANGED_ACTION。WifiLayer中注册了Action的Receiver。当WifiLayer收到此Action后开始scan的流程,具体如下

    当wpa_supplicant 处理完SCAN 命令后,它会向控制通道发送事件通知扫描完成,从wifi_wait_for_event 函数会接收到该事件,由此WifiMonitor 中的MonitorThread 会被执行来出来这个事件:

    配置 AP 参数:

    当用户在 WifiSettings 界面上选择了一个AP 后,会显示配置AP 参数的一个对话框:

    Wifi连接:

    IP地址的配置:

    首先交代开发环境——硬件平台:高通MSM8225,OS:Android2.3.5,无线模块:brodcom BCM4330。

    一、WIFI:

          首先保证上好电:在platform/kernel/arch/arm/mach-msm/board-msm7x30.c中实现GPIO管脚的配置,也要配置好休眠唤醒的脚。再就是在板级__init里面配置好WIFI的上电以及下电时序问题,还有因为我们的无线芯片是基于SDIO进行通讯的,所以SDIO的driver也要配置好。

           再就是WIFI本身的驱动的开发了,我们是用博通公司提供的代码,在dhd_custemer_gpio.c中修改好相应的Power_en和reset脚的配置,然后配置wlan linux相关的驱动。最终编译生成dhd.ko文件。

            这个dhd.ko文件和nvram.txt以及sdio.bin文件共同加载了wlan0的驱动。在中间层有一个hardware/library_lib/wifi/wifi.c,就是把一些配置文件的加载,DHCP文件的文件路径等等综合在一起。

             在wifi移植过程中一定要注意MAC地址的有效性和可用性。这样才能连接热点已经被分配到IP地址。

    二、Bluetooth:

            首先还是和wifi一样,上电是必须的!在platform/kernel/arch/arm/mach-msm/board-msm7x30.c中实现bluetooth_power_init,注意是在参数初始化的函数__init msm7x30_init函数中完成。

            由于BT的协议层,在开发的时候基本不用动什么,所以我们直接找跟芯片相关的文件进行修改。brodcom BT相关的文件在system/bluetooth/brcm_patchram_plus/

    brcm_patchram_plus.c 中,里面主要完成了如下事件:1、读取BT的地址。2、执行parse相关命令。3、重启HCI服务,4、设置蓝牙通信的波特率。5、设置hci_pcm

            再就是开启BT的服务。目录在system/core/rootdir/A1/etc/init.qcom.bt.sh 中,实现start_hciattach和kill_hciattach的功能。


    网上关于BT的驱动很少,所以我在开发过程中把其中的步骤记录下来。供大家相互学习讨论。


    一、关于BT driver的移植:


    1. Enablebluetootch in BoadConfig.mk

           BOARD_HAVE_BLUETOOTH := true


    2.实现BT电源管理rfkill驱动。

    Kernel/driver/bluetooth/bluetooth-power.c    高通的这个文件基本上不用动。

    在kernel\arch\arm\mach_msm7x27.c: static int bluetooth_power(int on)中

    实现:上电:把bt_reset pin 和bt_reg_on pin 拉低

                    mdelay(10);

                  把bt_resetpin 和bt_reg_on pin 拉高

                  mdelay(150)

          下电:把bt_reset pin 和bt_reg_on pin 拉低       

     

    3. RebuildAndroid image and reboot

    命令行测试:

    echo 0 >/sys/class/rfkill/rfkill0/state   //BT下电

    echo 1 >/sys/class/rfkill/rfkill0/state   //BT上电

    brcm_patchram_plus-d --patchram /etc/firmware/BCM4329B1_002.002.023.0061.0062.hcd/dev/ttyHS0

    hciattach -s115200 /dev/ttyHS0 any

    没任何错误提示是可以用以下测试

    hciconfig hci0up

    hcitool scan

     

    4.实现BT睡眠唤醒机制

    Kernel\drivers\bluetooth\bluesleep.c一般来说这个文件改动比较少,但可能逻辑上会有些问题。需要小的改动。

    在kernel\arch\arm\mach_xxx/board_xxx.c:bluesleep_resources中定义gpio_host_wake(BT唤醒host脚)、gpio_ext_wake(host唤醒BT脚)、host_wake(BT唤醒host的中断号)。

    注:各个平台的board_xxx.c文件名字不同,请客户确认 


    5.系统集成

    1)在init.qcom.rc中确认有下面的内容:

    service hciattach/system/bin/sh /system/etc/init.qcom.bt.sh

        user bluetooth

        group qcom_oncrpc bluetooth net_bt_admin

        disabled

        oneshot

     

    2)修改init.qcom.bt.sh

    确认有:

    BLUETOOTH_SLEEP_PATH=/proc/bluetooth/sleep/proto

    echo 1 >$BLUETOOTH_SLEEP_PATH

    /system/bin/hciattach-n /dev/ttyHS0 any 3000000 flow & 改为:

    ./brcm_patchram_plus--enable_lpm –enable_hci --patchram /system/etc/wifi/BCM4329BT.hcd --baudrate3000000 /dev/ttyHS0 &

    注掉:高通下载firmware的命令。

     

    6.重新编译system。此时BT应该能运行了。


    二、BT的休眠唤醒配置


    BT的休眠在driver/bluetooth/bluesleep.c中,首先驱动的名字叫“bluesleep”与arch/arm/mach-msm/board-msm7x30.c相匹配就执行platform_driver_probe(&bluesleep_driver, bluesleep_probe)然后调用static int __init bluesleep_probe(struct platform_device *pdev),这里会配置两个引脚HOST_WAKE_BT & BT_WAKE_HOST 

    bsi = kzalloc(sizeof(struct bluesleep_info), GFP_KERNEL);
            if (!bsi)
                    return -ENOMEM;

            res = platform_get_resource_byname(pdev, IORESOURCE_IO,
                                    "gpio_host_wake");
            if (!res) {
                    BT_ERR("couldn't find host_wake gpio\n");
                    ret = -ENODEV;
                    goto free_bsi;
            }
            bsi->host_wake = res->start;
            //[SIMT-zhangmin-111230] change the configuration of BT sleep gpio from bt_power to here {
            gpio_tlmm_config(GPIO_CFG(bsi->host_wake, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),GPIO_CFG_ENABLE);
            //[SIMT-zhangmin-111230] }
            ret = gpio_request(bsi->host_wake, "bt_host_wake");
            if (ret)
                    goto free_bsi;
            ret = gpio_direction_input(bsi->host_wake);

     bsi->host_wake_irq = platform_get_irq_byname(pdev, "host_wake");

    如上代码所示,主要将HOST_WAKE_BT设置为输出脚,BT_WAKE_HOST 设置为输入脚并也设置为中断脚,等待BT芯片的唤醒。

    然后再bluesleep_init函数中建立BT目录/proc/bluetooth/sleep/读btwake中HOST_WAKE_BT的状态。读出的状态值为0或1。

    或在BT目录/proc/bluetooth/sleep/写btwake中HOST_WAKE_BT的状态。写出状态值为0或1。


     Part 1 
    问:打开wifi,连接wifi热点,提示连接成功,但headbar上不显示wifi图标,back退出wifi设置,再进入,提示wifi已断开。
    答:首先现象复现,当现象复现时进入adb shell,然后输入ifconfig 查看是否有wlan0 端口,然后在adb shell 中ping 192.168.1.101(嵌入式设备的IP),如果能Ping通则说明底层wifi设备与AP是连接通的。所以把问题转向上层。上层在frameworks/base/services/java/com/android/server/ConnectivityService.java文件中查看private void handleDisconnect(NetworkInfo info)函数的实现,问题可能出现在这里。
    Part 2
    问:出现新热点,需要重启WIFI才可以扫描到。
    问:20s内无法连接到WIFI热点。
    问:已连接的热点关闭,不会自动连接下一个热点。
    答:这些问题都是供应商芯片的firmware没有配置好,所以直接找FAE换掉。
    Part 3
    问:调试中如果遇到dhd_sdio_probe fail 。
    问:发现sdio register timeout 。
    答:因为我们用到的WIFI数据通道是SDIO接口,所以要在log信息中查看sdcard是否有加载。没加载的话就看看WIFI芯片的上电(如WIFI_REG_ON这个PIN脚)。
    Part 4
    问:如果在wifi的设置里面选中wifi选项出现ERRO(或错误)的提示。
    答:首先在adb shell中lsmod查看.ko文件是否已经加载。如没加载cat /proc/kmsg查看是否是版本匹配的问题。如遇版本匹配则在kernel/scripts/setlocalversion中将echo “+”中去掉。如果顺利加载了驱动,则要看看MAC地址是否有,并且是否合理。
    Part 5
    问:发现在WIFI设置选项中有已经选上了wifi并且勾应打上了,过一会出现wifi的勾自动消失。
    答:这种情况在adb shell中用ifconfig查看Wlan的接口用的是否是wlan0,有可能是eth0。如果是eth0则在hardware/libhardware_legacy/wifi/wifi.c中的#define WIFI_DRIVER_MODULE_ARG  "firmware_path=/system/etc/firmware/wlan/sdio.bin nvram_path=/data/simcom/nvram.txt iface_name=wlan0" 中查看iface_name=wlan0是否已经加上。
    Part 6
    问:有的路由器不能扫描的到。
    答:查看wlan的设置的channel是否在1-14这个频段,因为如果wlan设置成USA模式则channel的范围在1-11之间,channel 12,13,14就不会收索的到。所以要在nvram.txt中修改成ccode=ALL,并且在gqcom_cfg.ini中把APCntryCode=ALL。这样应该就可以扫描到所有的channel了。当然如果上层还是没有收索到的话,在Settings.java中也要做相应的修改。
    常用的命令:wl channels_in_country
    wl chanlist
    wl channels

    wl country

    Part 7

    问:【预置条件】:wifi 已连接 wifi sleep policy模式为When screen turns off
            【操作步骤】:wifi连接网络,静置屏幕熄灭 大约5分钟,再次点亮屏幕
            【测试结果】:wifi一直处在scanning状态,无法连接网络,关闭再打开恢复正常
            【预期结果】:点亮屏幕后,wifi自动连接成功
    答:调试分析记录:
    1.在frameworks/base/services/java/com/android/server/WifiService.java中修改LCD灭屏后关掉WIFI的时间长短,由以前的2分钟修改为现在的1秒钟。
    结果是短时间休眠后唤醒可以顺利连上AP,但经过长时间休眠(如15分钟)后唤醒机器还是无法连接AP。
    2.检查Kernel中POWER_ON使能脚,看是否有其它地方被占用过,结果是屏蔽所有其它用到过该脚的代码还是无用。
    3.检查CP侧代码,将CP侧POWER_ON引脚由以前的某种特殊功能设置成普通的Output模式,然后AP就可以自由的控制其高低电平了。
    修改后的结果还是以无效告终。
    4.检查external/wpa_supplicant_6/wpa_supplicant/文件夹下面的代码,检查WEXT驱动代码。结果还是失败。
    5.最后在机器休眠15分钟后,用底层命令行来scan、连接等动作的操作,结果根本无法扫描到AP。故把问题集中在驱动底层。经过修改dhd.ko、sdio.bin文件
    现在此Bug终于得解。

    6.也有问题不出现在驱动dhd.ko文件中,可能出现在mmc驱动中的sdio通道。在函数mmc_pm_notify中当出现PM_POST_SUSPEND或PM_POST_HIBERNATION的情况时就有可能移除掉了sdio通道,所以函数mmc_detect_change(host, 0)要加一个判断,当sdio作为wifi通道时就不能移除。移除后的后果就是此Bug。



  • 相关阅读:
    设计模式复习-状态模式
    设计模式复习-观察者模式
    设计模式复习-建造者模式
    设计模式复习-外观模式
    推荐算法-协同过滤
    设计模式复习-模板方法模式
    设计模式复习-原型模式
    设计模式复习-代理模式
    神经网络与机器学习 笔记—泛化和交叉验证
    神经网络与机器学习 笔记—改善反向传播的性能试探法
  • 原文地址:https://www.cnblogs.com/yuzaipiaofei/p/4124167.html
Copyright © 2011-2022 走看看