wifi詳解(五)

1        Android平臺的Wifi模塊移植要點

1.1      Wifi結構

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的硬件芯片(是一個組合集成芯片)

1.2      Wifi模塊環境

Wifi模塊環境包括如下部分:

1.      bcm43xx驅動源碼

2.      wpa_supplicant和支持WAPI的wapilib庫

3.      nvram.txt(BCM43xx芯片配置文件)

4.      wpa_supplicant.conf和wifi固件

通常來講,第三和第四條件的文件在BCM43xx源碼中都有包含。

1.3      Wifi模塊的編譯

1.3.1       Wifi驅動源碼

這裏不以某個類型的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提供的驅動源碼可能的組織方式跟上面是有差異的,但大體的內容差很少,上面只是針對模塊源碼中目錄和文件的不一樣用途來講明的。

1.3.2       在android平臺添加BCM43xx驅動

要在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

1.3.3       編譯wifi驅動源碼

在編譯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文件生成,若是有,即代表編譯成功,不然查看編譯過程的出錯信息,解決錯誤問題再編譯,直至編譯成功。

1.3.4       在android中使用BCM43xx

前面的過程只是在android系統中添加編譯了BCM43xx驅動源碼,可是要想在android中使用它,還須要費一番功夫。須要修改的地方在開始的地方已經用藍色背景標註了,在這裏咱們要看看到底要修改哪些文件。

1.3.4.1        hardware/libhardware_legacy/wifi/wifi.c

爲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)

 

1.3.4.2        kernel/arch/arm/mach‐XXX/board‐XXXX.c

爲BCM43xx 驅動添加電源管理部份內容,這裏不詳細敘述。

1.3.4.3        system/core/rootdir/etc/init.xxx.rc 

爲支持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

......

1.3.4.4        vendor/XXXX/XXXX/BoardConfig.mk

爲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的支持也須要作一系列的修改,這裏再也不對其進行詳細的敘述了。

2        總結

最近一段時間裏對wifi模塊的學習,讓我對wifi有了更多的瞭解,但這些也是不夠的。對於wifi模塊,須要瞭解的東西不少,這裏只對其工做原理和工做流程以及移植過程進行了簡單的闡述,還有不少方面沒有歸納到,如:協議層的實現方式和過程,以及數據傳輸中的細節和SDIO相關內容等等,這些在實際的wifi模塊工做時可能都須要咱們去進一步的分析和把握,雖然對wifi的理解可能不到位,但對這段時間學習作一次總結,也是大有裨益的,但願有機會能夠更深刻的學習wifi模塊。

在wifi模塊調試的過程當中也會出現一系列的問題,這些問題能夠概括成不一樣的類型,對這些類型的問題作分析和總結,能夠幫助咱們在之後調試工做中快速定位問題所在。

對wifi的瞭解還遠遠不夠,但願和wifi感興趣的和已經成爲高手的同仁能有更多的交流。

相關文章
相關標籤/搜索