user interfacelinux
Android WiFiServiceandroid
WPA_Supplicantshell
DHD Drivervim
Dongle Binaryapi
BCM43xxHardwareapp
藍色:須要修改socket
黑色:不須要修改ide
藍色部分是爲了在android環境下,支持bcm43xx芯片須要修改的部分,各個部分的功能以下:函數
1. User interface(用戶接口層):控制和設置wifi的用戶接口層學習
2. Android wifi service:它是android系統中的wifi服務部分,主要用來啓動和中止wpa_supplicant,並做爲用戶接口層和wpa_supplicant交互的橋樑存在
3. Wpa_supplicant:支持wpa和wapi的外部庫
4. Dhd driver:wifi模塊的驅動
5. Dongle binary:BCM43xx的固件
6. BCM43xx:wifi的硬件芯片(是一個組合集成芯片)
Wifi模塊環境包括如下部分:
1. bcm43xx驅動源碼
2. wpa_supplicant和支持WAPI的wapilib庫
3. nvram.txt(BCM43xx芯片配置文件)
4. wpa_supplicant.conf和wifi固件
通常來講,第三和第四條件的文件在BCM43xx源碼中都有包含。
這裏不以某個類型的BCM43xx芯片和android版本做爲特例來說解wifi模塊的編譯過程,只是對編譯的通用部分作簡要的說明。
通常來講,wifi模塊的編譯可採用兩種紅方式:一是內部編譯,二是模塊編譯。一般使用的是模塊編譯,這裏也以模塊編譯wifi模塊爲例來講明wifi模塊的編譯過程。
在wifi模塊驅動源碼中,主要包含如下幾個目錄:
Firmware:裏面會提供對應BCM43xx芯片的固件
Config:提供wpa_supplicant.conf和nvram.txt以及dhcpcd.conf,還有android.mk文件。若是沒有上面的配置文件,須要找到放入該目錄。
Android.mk:這是一個文件,也是編譯android平臺編譯wifi模塊的入口
Src:wifi驅動的源碼目錄
其實,你看到的broadcom提供的驅動源碼可能的組織方式跟上面是有差異的,但大體的內容差很少,上面只是針對模塊源碼中目錄和文件的不一樣用途來講明的。
要在android平臺編譯wifi模塊,首先要將wifi模塊的源碼添加到android平臺下的目錄中。至於添加到什麼地方也不是固定的,通常會添加到vendor目錄下的某個目錄下,下面咱們把BCM43xx模塊源碼放在vendor/xxxx/wlan/bcm43xx下(XXXXX表明產品名稱)。要知道,在添加源碼以前,這個bcm43xx目錄是不存在的,須要手動建立,並在該目錄下建立android和src兩個目錄:
PC$ cd<ANDROID_ROOT>
PC$ mkdir ‐p vendor/xxxx/wlan/bcm4325/
PC$ cdvendor/xxxx/wlan/bcm4325/
PC$ mkdirandroid src
PC$ ls
android src
在建立好上面的目錄後,就能夠在目錄下添加BCM43xx的相關源碼了,src存放的是驅動源碼,android目錄下主要存放固件(即二級制鏡像),編譯文件(Android.mk),配置文件(nvram.txt和wpa_supplicant.conf)等。
添加好相關源碼後,還須要作必定的修改工做(主要對編譯文件的修改),否則模塊沒法被正常編譯的,Android.mk的內容修改操做以下。
PC$ cp<WORK>/bcm4325_source/open‐src/src/dhd/android/config/Android.mk
<ANDROID_ROOT>/vendor/xxxx/wlan/bcm4325/android
PC$ cd<ANDROID_ROOT>/vendor/xxxx/wlan/bcm4325/android
PC$ viAndroid.mk //到這裏,找到Android.mk文件,文件內容以下
……
#
# Install WLAN Driver, firmware, and configurationfiles.
#
local_target_dir :=$(TARGET_OUT_ETC)/firmware //這裏定義local_target_dir的路徑,在後面會用到
########################
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE :=sdio-g-cdc-reclaim-idsup-wme-ccx-wapi.bin
LOCAL_MODULE_TAGS := user development
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(local_target_dir)
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
########################
include $(CLEAR_VARS)
LOCAL_MODULE := nvram_4325b0.txt
LOCAL_MODULE_TAGS := user development
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(local_target_dir)
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
########################
include $(CLEAR_VARS)
LOCAL_MODULE := dhd.ko
LOCAL_MODULE_TAGS := user development
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH :=$(TARGET_OUT)/lib/modules
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
########################
include $(CLEAR_VARS)
LOCAL_MODULE := wpa_supplicant.conf
LOCAL_MODULE_TAGS := user development
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/wifi
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
########################
include $(CLEAR_VARS)
LOCAL_MODULE := dhcpcd.conf
LOCAL_MODULE_TAGS := user development
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH :=$(TARGET_OUT_ETC)/dhcpcd
LOCAL_SRC_FILES := android_dhcpcd.conf
include $(BUILD_PREBUILT)
########################
對上面的內容有必要說明一下:LOCAL_MODULE和LOCAL_MODULE_PATH的定義是這裏須要修改的地方。對於LOCAL_MODULE_PATH的修改時必定的,但它主要依賴與android平臺已經定義好的一些變量,如:TARGET_OUT _ETC和TARGET_OUT等。LOCAL_MODULE定義的是要操做的對象,也是前面提到的配置文件,編譯好的驅動模塊二進制文件和固件等。
該文件的做用:將各個文件拷貝到定義的地方,以供驅動模塊和wpa_supplicant等使用。、
對於驅動的源碼,用戶能夠經過定製的wifi芯片管理函數來關閉和開啓wifi模塊,在dhd/sys/dhd_custom_gpio.c文件中有以下的函數定義:
#define CUSTOMER_HW
#ifdef CUSTOMER_HW
extern void bcm_wlan_power_off(int);
BCM43xx BCM43xx Porting Guide for Android System
Broadcom Corporation Proprietary and Confidential
9
extern void bcm_wlan_power_on(int);
#endif /* CUSTOMER_HW */
因此用戶可使用本身定製的開關函數,或者使用BCM43xx自帶的開關函數來控制wifi模塊的開關。若是使用定製的開關函數,則須要在平臺相關的代碼中定義這兩個函數:
Path:kernel/arch/arm/mach‐XXX/board‐XXXX.c
……
void bcm_wlan_power_off(int onoff);
void bcm_wlan_power_on(int onoff);
……
前面的Android.mk的修改中,有對dhd.ko的拷貝操做,這就是說源碼編譯後生成的模塊二進制文件應該被暫時拷貝到Android.mk中指示的地方。這個暫時拷貝操做在驅動源碼的編譯文件dhd/linux/Makefile中被執行。
PC$ cd<ANDROID_ROOT>/vendor/xxxx/wlan/bcm4325/src
PC$ vi dhd/linux/Makefile +315
modules: $(OFILES)
test -r ./Makefile || ln –s $(SRCBASE)/dhd/linux/makefile.26./Makefile
$(MAKE) -C $(LINUXDIR) M=$(shell pwd) $(if $(VERBOSE),V=1)modules
cp $(KMODULES) $(SRCBASE)/../android/.
下一步須要作的就是將wifi模塊源碼的頂層目錄下的android.mk文件放到bcm43xx目錄下,它是android編譯入口文件,表示在編譯android時,這個wifi驅動模塊被包含到整個android編譯系統中。它的內容以下:
PC$ cd <ANDROID_ROOT>/vendor/xxxx/wlan/bcm4325/
PC$ vim Android.mk
ifeq ($(BOARD_WLAN_DEVICE),bcm43xx)
include $(callall-subdir-makefiles)
endif
很簡單,若是被BOARD_WLAN_DEVICE被定義爲bcm43xx,調用call all-subdir-makefiles函數來包含全部子目錄下的Android.mk文件,這是android編譯系統的規則。
那麼,最後一步就是在相關的平臺配置文件中定義BOARD_WLAN_DEVICE爲bcm43xx,文件路徑:vendor/XXXX/XXXX/BoardConfig.mk。
在編譯wifi驅動源碼以前,首先要創建kernel環境,即要在編譯wifi模塊以前編譯kernel,由於模塊的編譯時依賴與內核的。
內核的編譯以下:
PC$ cd <ANDROID_ROOT>/kernel
PC$ make ARCH=arm CROSS_COMPILE=<ANDROID_ROOT>/prebuilt/
linuxx86/toolchain/arm‐eabi‐4.4.0/bin/arm‐eabi‐ XXXX_defconfig
PC$ make ARCH=armCROSS_COMPILE=<ANDROID_ROOT>/prebuilt/
linuxx86/toolchain/arm‐eabi‐4.4.0/bin/arm‐eabi‐ zImage
若是設置好了ARCH和CROSS_COMPILE的環境變量,就能夠省略這兩個選項的定義,直接使用make命令生成zImage了。
在編譯好kernel以後,就能夠進入bcm43xx源碼目錄dhd/linux下,這裏面有兩個文件Makefile和Makefile.26,若是沒有Makefile文件就將Makfeile.26拷貝成Makfile文件(其實是創建了一個符號連接文件),固然也要作前面的dhd.ko暫時拷貝命令的添加了。在該目錄下輸入以下命令編譯模塊源碼:
PC$ cd<ANDROID_ROOT>/vendor/xxxx/wlan/bcm4325/src
PC$ cd dhd/linux/
PC$ make ARCH=armLINUXDIR=<ANDROID_ROOT>/kernel
CROSS_COMPILE=<ANDROID_ROOT>/prebuilt/linux‐x86/toolchain/arm‐eabi‐
4.4.0/bin/arm‐eabi‐ dhd‐cdc‐sdmmc‐gpl
最後一條命令增長了一個命令選項LINUXDIR的傳值,即告訴該編譯文件kernel的所在位置,進入kernel的Makefile文件作設置工做,而後返回該目錄下的Makefile文件進行編譯工做。
到這裏bcm43xx驅動源碼已經編譯完成,能夠到android目錄下查看有沒有dhd.ko文件生成,若是有,即代表編譯成功,不然查看編譯過程的出錯信息,解決錯誤問題再編譯,直至編譯成功。
前面的過程只是在android系統中添加編譯了BCM43xx驅動源碼,可是要想在android中使用它,還須要費一番功夫。須要修改的地方在開始的地方已經用藍色背景標註了,在這裏咱們要看看到底要修改哪些文件。
爲BCM43xx驅動模塊作適當修改。Wifi.c做爲加載wifi驅動模塊和啓動關閉wpa_supplicant的重要角色而存在,爲了使wifi能更好的工做,該文件中的一些變量參數必須被適當的設置(根據wpa_supplicant.conf)。
PC$ vi hardware/libhardware_legacy/wifi/wifi.c
......
#define WIFI_DRIVER_MODULE_PATH
"/system/lib/modules/dhd.ko"
......
#define WIFI_DRIVER_MODULE_NAME"dhd"
......
#define WIFI_DRIVER_MODULE_ARG
"firmware_path=/etc/firmware/sdio-g-cdc-reclaim-idsup-wme-ccxwapi.
bin nvram_path=/etc/firmware/nvram_4325b0.txt"
......
#define WIFI_TEST_INTERFACE "eth0"
......
static const char IFACE_DIR[] = "";
......
static const char SUPP_CONFIG_TEMPLATE[]=
"/data/misc/wifi/wpa_supplicant.conf";
……
static const char SUPP_CONFIG_FILE[] =
"/etc/wifi/wpa_supplicant.conf";
......
上面的紅色部分,就是對wifi驅動的特殊化定義,不一樣的wifi驅動會有不一樣的定義。修改還包括了固件的和配置文件的路徑,以及接口名的相關定義。
WIFI_TEST_INTERFACE定義的是wpa_supplicant和UI的交互接口名,當經過property_get()函數獲取wifi接口名錯誤時,就會使用此定義的接口名。Property_get()函數獲取的接口名,就是init.xx.rc文件中的接口定義的wifi.interface:
Setprop wifi.interface 「eth0」
SUPP_CONFIG_TEMPLATE定義的是wpa_supplicant配置文件的臨時文件。而SUPP_CONFIG_FILE定義的是wpa_supplicant運行時使用的配置文件,而且對wifi配置的修改也會保持到這個文件裏。
IFACE_DIR是wpa_supplicant控制接口的目錄,該目錄下的接口被UI用來鏈接到wpa_supplicant,這個目錄是由wpa_supplicant決定的,其實,這個接口其實是一個socket,在wpa_supplicant啓動時被建立,wpa_supplicant_ctrl_iface_init()
中有兩種方式來建立這個socket接口:
(1)android系統的socket
它使用wpa_%ctrl_interface%組合來定義本身的名字,經過socketwpa_eth0 dgram ...命令來生成的(在init.rc中),若是使用這種socket,下面的代碼中的接口名必須是一直的:
ctrl_interface=eth0 (In wpa_supplicant.conf)
"socket wpa_eth0 ..." (In init.*.rc )
setprop wifi.interface "eth0" (In init.*.rc)
wpa_supplicant ‐ieth0 ... (In init.*.rc)
此時,IFACE_DIR的定義爲NULL。
(2)特殊socket
Wpa_supplicant會經過wpa_supplicant.conf中的ctrl_interface目錄來建立控制接口socket,而這個值通常被定義爲:"ctrl_interface=DIR=/data/misc/....",這個socket的名字由wpa_supplicant的「-i」參數傳遞,若是使用這種方式的socket,下面的變量定義必須一致:
ctrl_interface=DIR=/data/misc/ (In wpa_supplicant.conf)
IFACE_DIR=/data/misc/ (In wifi.c)
爲BCM43xx 驅動添加電源管理部份內容,這裏不詳細敘述。
爲支持BCM43xx驅動模塊,修改wpa_supplicant服務。Init.xxx.rc文件的內容通常以下所示:
PC$ vi system/core/rootdir/etc/init.xxx.rc
...... //添加android系統接口
# to enable wifi
setprop wifi.interface "eth0"
# end of wifi
...... //修改wpa_supplicant.conf的權限
chmod 0660 /etc/wifi/wpa_supplicant.conf
chown wifi wifi /etc/wifi/wpa_supplicant.conf
...... //wpa_supplicant服務的啓動命令
service wpa_supplicant /system/bin/logwrapper
/system/bin/wpa_supplicant -Dwext -ieth0 -
c/etc/wifi/wpa_supplicant.conf
...... //給wpa_supplicant修改socket接口
socket wpa_eth0 dgram 660 wifi wifi
...... //修改dhcp接口
service dhcpcd /system/bin/dhcpcd -BKL eth0
......
爲BCM43xx驅動添加配置變量。
PC$ vi vendor/XXXX/XXXX/BoardConfig.mk
……
ifneq ($(BUILD_TINY_ANDROID), true)
……
BOARD_WPA_SUPPLICANT_DRIVER := WEXT
BOARD_WLAN_DEVICE := bcm43xx
endif # !BUILD_TINY_ANDROID
……
對BCM43xx的WAPI的支持也須要作一系列的修改,這裏再也不對其進行詳細的敘述了。
最近一段時間裏對wifi模塊的學習,讓我對wifi有了更多的瞭解,但這些也是不夠的。對於wifi模塊,須要瞭解的東西不少,這裏只對其工做原理和工做流程以及移植過程進行了簡單的闡述,還有不少方面沒有歸納到,如:協議層的實現方式和過程,以及數據傳輸中的細節和SDIO相關內容等等,這些在實際的wifi模塊工做時可能都須要咱們去進一步的分析和把握,雖然對wifi的理解可能不到位,但對這段時間學習作一次總結,也是大有裨益的,但願有機會能夠更深刻的學習wifi模塊。
在wifi模塊調試的過程當中也會出現一系列的問題,這些問題能夠概括成不一樣的類型,對這些類型的問題作分析和總結,能夠幫助咱們在之後調試工做中快速定位問題所在。
對wifi的瞭解還遠遠不夠,但願和wifi感興趣的和已經成爲高手的同仁能有更多的交流。