1、修改 device/fsl/sabresd_6dq/BoardConfig.mk ,添加下面部分
#for broadcom ap6181 vendor
# Wifi
BOARD_WLAN_VENDOR := BROADCOM
#for broadcom vendor
ifeq ($(BOARD_WLAN_VENDOR),BROADCOM)
WPA_SUPPLICANT_VERSION := VER_0_8_X
HOSTAPD_VERSION := VER_0_8_X
BOARD_WPA_SUPPLICANT_DRIVER := NL80211
BOARD_HOSTAPD_DRIVER := NL80211
BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_bcmdhd
BOARD_HOSTAPD_PRIVATE_LIB := lib_driver_cmd_bcmdhd
BOARD_WLAN_DEVICE := bcmdhd
WIFI_DRIVER_FW_PATH_PARAM := "/sys/module/bcmdhd/parameters/firmware_path"
WIFI_DRIVER_FW_PATH_STA := "/system/etc/firmware/fw_bcm40181a2.bin"
WIFI_DRIVER_FW_PATH_P2P := "/system/etc/firmware/fw_bcm40181a2_p2p.bin"
WIFI_DRIVER_FW_PATH_AP := "/system/etc/firmware/fw_bcm40181a2_apsta.bin"
WIFI_DRIVER_MODULE_NAME := "bcmdhd"
WIFI_DRIVER_MODULE_PATH := "/system/lib/modules/bcmdhd.ko"
WIFI_DRIVER_MODULE_ARG := "iface_name=wlan0 firmware_path=/system/etc/firmware/fw_bcm40181a2.bin nvram_path=/system/etc/firmware/nvram.txt"
TARGET_KERNEL_MODULES := \
kernel_imx/drivers/net/wireless/bcmdhd/bcmdhd.ko:system/lib/modules/bcmdhd.ko
include hardware/broadcom/Android.mk
include hardware/broadcom/wlan/bcmdhd/config/config-bcm.mk
endif
2、修改 hardware/broadcom/wlan/bcmdhd/config/config-bcm.mk
########################
PRODUCT_COPY_FILES += \
hardware/broadcom/wlan/bcmdhd/config/wpa_supplicant_overlay.conf:system/etc/wifi/wpa_supplicant_overlay.conf \
hardware/broadcom/wlan/bcmdhd/config/p2p_supplicant_overlay.conf:system/etc/wifi/p2p_supplicant_overlay.conf
########################
3、修改 external/wpa_supplicant_8/wpa_supplicant/wpa_supplicant.conf
#####wpa_supplicant configuration file template #####
update_config=1
ctrl_interface=wlan0
eapol_version=1
ap_scan=1
fast_reauth=1
4、修改 hardware/broadcom/wlan/bcmdhd/config/wpa_supplicant_overlay.conf
disable_scan_offload=1
p2p_disabled=1
5、修改 hardware/broadcom/wlan/bcmdhd/config/p2p_supplicant_overlay.conf
disable_scan_offload=1
6、修改 device/fsl/sabresd_6dq/init.rc
on post-fs-data
mkdir /data/misc/wifi 0770 wifi wifi
mkdir /data/misc/wifi/sockets 0770 wifi wifi
mkdir /data/misc/dhcp 0770 dhcp dhcp
on boot
########## 3.0.x <= kernel version <= 3.4.x ##########
service wpa_supplicant /system/bin/wpa_supplicant \
-iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \
-I/system/etc/wifi/wpa_supplicant_overlay.conf \
-O/data/misc/wifi/sockets \
-e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0
# we will start as root and wpa_supplicant will switch to user wifi
# after setting up the capabilities required for WEXT
# user wifi
# group wifi inet keystore
class main
socket wpa_wlan0 dgram 660 wifi wifi
disabled
oneshot
service p2p_supplicant /system/bin/wpa_supplicant \
-iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \
-I/system/etc/wifi/wpa_supplicant_overlay.conf -N \
-ip2p0 -Dnl80211 -c/data/misc/wifi/p2p_supplicant.conf \
-I/system/etc/wifi/p2p_supplicant_overlay.conf \
-O/data/misc/wifi/sockets -puse_p2p_group_interface=1 \
-e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0
# we will start as root and wpa_supplicant will switch to user wifi
# after setting up the capabilities required for WEXT
# user wifi
# group wifi inet keystore
class main
socket wpa_wlan0 dgram 660 wifi wifi
disabled
oneshot
service dhcpcd_wlan0 /system/bin/dhcpcd -ABKL
class main
disabled
oneshot
service dhcpcd_p2p /system/bin/dhcpcd -aABKL
class main
disabled
oneshot
service iprenew_wlan0 /system/bin/dhcpcd -n
class main
disabled
oneshot
service iprenew_p2p /system/bin/dhcpcd -n
class main
disabled
oneshot
因为Android连接WiFi需要用到wpa_supplicant这个工具,并且Android源码中自带了这个,但不知道什么原因,这个工具一直编译不过,所以只能想办法把这个工具整个目录替换掉,编译下OK了,在Android设置界面中打开WiFi,串口信息可以看到WiFi驱动已经挂载成功了 ,但屏幕一直显示失败。但是一度怀疑是wpa这个工具的问题,因为毕竟用的不是Android源码自带的那个,在网上通过查找资料,发现了一种可以用命令通过wpa_supplicant 连接WiFi,详细步骤见早先博文。
通过命令测试,通过wpa_supplicant 是可以扫描连接WiFi的,并且可以ping通网关,说明wpa_supplicant 这个工具是OK了
既然工具OK 驱动OK ,那就是Android配置问题了,在参考迟来的官方移植文档后,WiFi设置界面终于可以看到扫描的WiFi热点了,并且能成功的连接到WiFi,这是个激动人心的消息------------历史性的进步,也说明了及时资料可以省下不少时间。
在WiFi连接OK后,不久就发现了一个问题,就是在Android设置界面中第一次打开WiFi是OK的,没任何问题,然而关闭后再打开,WiFi就挂了,查看串口,发现是因为WiFi驱动没有释放总线,也就是在WiFi设置中关闭WiFi后,驱动并没有真正卸载,所以导致第二次开启WiFi时无法挂载驱动。发现问题后就一直想着如何能真正卸载WiFi驱动,咨询了模块厂家,他们给出的结论是 需要把平台sdio detect和remove函数有分别加到dhd_gpio.c的bcm_wlan_power_on和bcm_wlan_power_off 中,但由于水平有限,一直找不到现在使用的平台中关于SDIO 的detect 和remove函数。
后来看到以前Android移植WiFi的帖子中,有人在wifi.c中的 wifi_load_driver 和 wifi_unload_driver 直接 return 0; 当时移植时并不知道这是什么意思,所以没太在意,因为没有去阅读源码。 后来仔细一看,原来如此:
int wifi_load_driver()
{
#ifdef WIFI_DRIVER_MODULE_PATH
char driver_status[PROPERTY_VALUE_MAX];
int count = 100; /* wait at most 20 seconds for completion */
if (is_wifi_driver_loaded()) {
return 0;
}
if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0)
return -1;
if (strcmp(FIRMWARE_LOADER,"") == 0) {
/* usleep(WIFI_DRIVER_LOADER_DELAY); */
property_set(DRIVER_PROP_NAME, "ok");
}
else {
property_set("ctl.start", FIRMWARE_LOADER);
}
sched_yield();
while (count-- > 0) {
if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
if (strcmp(driver_status, "ok") == 0)
return 0;
else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) {
wifi_unload_driver();
return -1;
}
}
usleep(200000);
}
property_set(DRIVER_PROP_NAME, "timeout");
wifi_unload_driver();
return -1;
#else
property_set(DRIVER_PROP_NAME, "ok");
return 0;
#endif
}
int wifi_unload_driver()
{
usleep(200000); /* allow to finish interface down */
#ifdef WIFI_DRIVER_MODULE_PATH
if (rmmod(DRIVER_MODULE_NAME) == 0) {
int count = 20; /* wait at most 10 seconds for completion */
while (count-- > 0) {
if (!is_wifi_driver_loaded())
break;
usleep(500000);
}
usleep(500000); /* allow card removal */
if (count) {
return 0;
}
return -1;
} else
return -1;
#else
property_set(DRIVER_PROP_NAME, "unloaded");
return 0;
#endif
}
所以解决办法是:
int wifi_load_driver()
{
//#ifdef WIFI_DRIVER_MODULE_PATH
#if 0
char driver_status[PROPERTY_VALUE_MAX];
int count = 100; /* wait at most 20 seconds for completion */
if (is_wifi_driver_loaded()) {
return 0;
}
if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0)
return -1;
if (strcmp(FIRMWARE_LOADER,"") == 0) {
/* usleep(WIFI_DRIVER_LOADER_DELAY); */
property_set(DRIVER_PROP_NAME, "ok");
}
else {
property_set("ctl.start", FIRMWARE_LOADER);
}
sched_yield();
while (count-- > 0) {
if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
if (strcmp(driver_status, "ok") == 0)
return 0;
else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) {
wifi_unload_driver();
return -1;
}
}
usleep(200000);
}
property_set(DRIVER_PROP_NAME, "timeout");
wifi_unload_driver();
return -1;
#else
property_set(DRIVER_PROP_NAME, "ok");
return 0;
#endif
}
int wifi_unload_driver()
{
usleep(200000); /* allow to finish interface down */
//#ifdef WIFI_DRIVER_MODULE_PATH
#if 0
if (rmmod(DRIVER_MODULE_NAME) == 0) {
int count = 20; /* wait at most 10 seconds for completion */
while (count-- > 0) {
if (!is_wifi_driver_loaded())
break;
usleep(500000);
}
usleep(500000); /* allow card removal */
if (count) {
return 0;
}
return -1;
} else
return -1;
#else
property_set(DRIVER_PROP_NAME, "unloaded");
return 0;
#endif
}
总结:
在做整个项目下来,因为是第一次接触到Android,所以很多东西都是云里雾里的,在Linux驱动部分每次都能很快的发现和定位到问题,虽然工作量不是特别大,但也是一个接触Android的一个开始吧,从一开始什么都不会,到慢慢了解Android源码结构,之后自己会修改一些小东西,例如开机logo、上下状态栏,之后到WiFi移植,虽然WiFi这部分花费了不少时间,但至少算是一个好的开始吧。在WiFi移植这段时间,深刻意识到资料的及时性真的可以节约不少时间,如果一开始就能拿到供应商的移植文档,应该一周甚至更短时间内就能解决,要少走很多弯路。当然WiFi这块,花费了这么长的时间也还是有所收获的 ,至少将WiFi驱动的源码弄明白是怎么回事了,也清楚的记得了Android中WiFi部分的源码结构和组成。
再一个就是通过这次WiFi的教训,明白了思考问题的角度应该多面化,不要只局限一个角度,就像这次WiFi驱动卸载的问题,一开始认定的想法就是如何去卸载WiFi这个模块,尽阅读了很多资料,也试过很多方法,但最终还是没能成功。当时也没去想为什么要卸载这个呢,事后一想这WiFi驱动在开机时就挂载上去之后就不在卸载一直到关机,其实这样对系统没任何负担和影响。也算是给自己一个教训吧 ,遇到问题从多方面去思考,甚至是背向思考,才能更快更好的定位和解决问题,bingo!