kinila 发表于 2015-10-2 07:05:27

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=&quot;android.permission.CHANGE_NETWORK_STATE&quot;>
</uses-permission>修改网络状态的权限
<uses-permission
android:name=&quot;android.permission.CHANGE_WIFI_STATE&quot;>
</uses-permission>修改WIFI状态的权限
<uses-permission android:name=&quot;android.permission.ACCESS_NETWORK_STATE&quot;>
</uses-permission>访问网络权限
<uses-permission android:name=&quot;android.permission.ACCESS_WIFI_STATE&quot;>
  </uses-permission>访问WIFI权限
  
  WIFI 核心模块
  nWifiService
  由SystemServer启动的时候生成的ConnecttivityService创建,负责启动关闭wpa_supplicant,启动和关闭WifiMonitor线程,把命令下发给wpa_supplicant以及跟新WIFI的状态
  nWifiMonitor
  负责从wpa_supplicant接收事件通知
  nWpa_supplicant
  1、读取配置文件
  2、初始化配置参数,驱动函数
  3、让驱动scan当前所有的bssid
  4、检查扫描的参数是否和用户设置的想否
  5、如果相符,通知驱动进行权限 认证操作
  6、连上AP
  nWifi驱动模块
  厂商提供的source,主要进行load firmware和kernel的wireless进行通信
  nWifi电源管理模块
  主要控制硬件的GPIO和上下电,让CPU和Wifi模组之间通过sdio接口通信
  
  Wifi工作步骤
  nWifi模块初期化
  nWifi启动
  n查找热点(AP)
  n配置AP
  n配置AP参数
  nWifi连接
  nIP地址配置
  
  Wifi模块代码总结
  nWifi Application代码
  packages/apps/Settings/src/com/android/settings/wifi
  nWifi Framework
  frameworks/base/wifi/java/android/net/wifi
  frameworks/base/services/java/com/android/server
  nWifi JNI
  frameworks/base/core/jni/android_net_wifi_Wifi.cpp
  nWifi Hardware
  hardware/libhardware_legacy/wifi/wifi.c
  nWifi tool
  external/wpa_supplicant
  nWifi 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 内核模块(该模块的位置硬编码为&quot;/system/lib/modules/wlan.ko&quot;), 然后启动wpa_supplicant ( 配置文件硬编码为&quot;/data/misc/wifi/wpa_supplicant.conf&quot;),再通过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,
                              &quot;gpio_host_wake&quot;);
      if (!res) {
                BT_ERR(&quot;couldn't find host_wake gpio\n&quot;);
                ret = -ENODEV;
                goto free_bsi;
      }
      bsi->host_wake = res->start;
      // 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);
      // }
      ret = gpio_request(bsi->host_wake, &quot;bt_host_wake&quot;);
      if (ret)
                goto free_bsi;
      ret = gpio_direction_input(bsi->host_wake);

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

如上代码所示,主要将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(NetworkInfoinfo)函数的实现,问题可能出现在这里。
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 “&#43;”中去掉。如果顺利加载了驱动,则要看看MAC地址是否有,并且是否合理。
Part 5
问:发现在WIFI设置选项中有已经选上了wifi并且勾应打上了,过一会出现wifi的勾自动消失。
答:这种情况在adb shell中用ifconfig查看Wlan的接口用的是否是wlan0,有可能是eth0。如果是eth0则在hardware/libhardware_legacy/wifi/wifi.c中的#define WIFI_DRIVER_MODULE_ARG&quot;firmware_path=/system/etc/firmware/wlan/sdio.bin nvram_path=/data/simcom/nvram.txt iface_name=wlan0&quot; 中查看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。
  
页: [1]
查看完整版本: Android Wifi BT的工作流程和porting(精)