移植MT76x8 私有WIFI驅動V4.1.0.0到Openwrt 18.06所遇到的坑

Openwrt系統,路由或者IOT網關方面,市面上能供個人或者小團隊甚至小企業 ,可玩性高的也就MT76xx系列路由芯片了,其中很大一部分原因主要在於MTK的WIFI驅動管控不是很嚴格,相對較容易獲取其WIFI驅動源碼。

目前市場上的MT76x8板子,帶私有WIFI驅動且性能較好的,大多停留都在Openwrt 15.05分支,內核相對來說較低(其實完全夠用)。

隨着Openwrt與LEDE的戰火停息,雙方交好,跟談戀愛一樣,其發展甚快,kernel版本也上升到4.14。但是很可惜啊,WIFI 驅動跟不上,官網的MT76 開源驅動,改善雖有,但穩定性尤其是帶寬較低,大概只有10Mb左右,穩定性在18.02上好像有比較大改善。

鑑於之前項目中用到過MTK私有驅動V.4.1.0.0版本,速率和穩定性還不錯(其實也就是市面上使用15.05分支的一些板子所用到的驅動,典型的比如wrtnode,widora等團隊),最近也稍稍有空,因此就考慮把驅動移植一把試試看。

首先要做的就是搞定Makefile中那一些亂七八糟的宏定義,說實話,MTK的宏使用的真有點過分(不過能有更好的辦法麼)

我們先看一下編譯源碼所用的Makefile什麼樣(由於太長,截取部分)


EXTRA_CFLAGS = -Idrivers/net/wireless/mt_wifi/include \
				-Idrivers/net/wireless/mt_wifi/embedded/include \
				-Idrivers/net/wireless/mt_wifi/ate/include

ifeq ($(CONFIG_SUPPORT_OPENWRT),y)
EXTRA_CFLAGS = -I$(src)/../src/include \
				-I$(src)/../src/embedded/include \
				-I$(src)/../src/ate/include
DRV_NAME = mt7628
SRC_DIR = ../src/embedded
obj-m += $(DRV_NAME).o
else
EXTRA_CFLAGS = -Idrivers/net/wireless/mt_wifi/include \
				-Idrivers/net/wireless/mt_wifi/embedded/include \
				-Idrivers/net/wireless/mt_wifi/ate/include
DRV_NAME = mt_wifi
SRC_DIR = ../mt_wifi/embedded
obj-$(CONFIG_MT_AP_SUPPORT) += $(DRV_NAME).o
endif

########################################################
# Common files
########################################################
cmm_objs := $(SRC_DIR)/common/crypt_md5.o\
						$(SRC_DIR)/common/crypt_sha2.o\
						$(SRC_DIR)/common/crypt_hmac.o\
						$(SRC_DIR)/common/crypt_aes.o\
						$(SRC_DIR)/common/crypt_arc4.o\
						$(SRC_DIR)/common/mlme.o\
						$(SRC_DIR)/common/cmm_wep.o\
						$(SRC_DIR)/common/action.o\

ifeq ($(CONFIG_MT_MAC),y)
	EXTRA_CFLAGS += -DMT_PS
	spec_objs += $(SRC_DIR)/common/mt_ps.o
	spec_objs += $(SRC_DIR)/common/mt_io.o
	spec_objs += $(SRC_DIR)/tx_rx/txs.o
endif



########################################################
# AP feature related files
########################################################
ap_objs := $(SRC_DIR)/ap/ap.o\
            $(SRC_DIR)/ap/ap_assoc.o\
            $(SRC_DIR)/ap/ap_auth.o\
            $(SRC_DIR)/ap/ap_connect.o\
            $(SRC_DIR)/ap/ap_mlme.o\
            $(SRC_DIR)/ap/ap_sanity.o\
            $(SRC_DIR)/ap/ap_sync.o\
            $(SRC_DIR)/ap/ap_wpa.o\
            $(SRC_DIR)/ap/ap_data.o\
            $(SRC_DIR)/ap/ap_autoChSel.o\
            $(SRC_DIR)/ap/ap_qload.o\
            $(SRC_DIR)/ap/ap_cfg.o\
            $(SRC_DIR)/ap/ap_nps.o\
            $(SRC_DIR)/os/linux/ap_ioctl.o            

ifeq ($(CONFIG_QOS_DLS_SUPPORT),y)
    EXTRA_CFLAGS += -DQOS_DLS_SUPPORT
    ap_objs += $(SRC_DIR)/ap/ap_dls.o
endif

ifeq ($(CONFIG_MBSS_SUPPORT),y)
    EXTRA_CFLAGS += -DMBSS_SUPPORT

    ifeq ($(CONFIG_NEW_MBSSID_MODE),y)
        EXTRA_CFLAGS += -DNEW_MBSSID_MODE
        ifeq ($(CONFIG_ENHANCE_NEW_MBSSID_MODE),y)
            EXTRA_CFLAGS += -DENHANCE_NEW_MBSSID_MODE
        endif
    endif

    ap_objs += $(SRC_DIR)/ap/ap_mbss.o\
            $(SRC_DIR)/ap/ap_mbss_inf.o
endif


########################################################
# chip related files
########################################################
ifeq ($(CONFIG_RALINK_MT7628),y)
EXTRA_CFLAGS += -DMT7628 -DMT_BBP -DMT_RF -DRTMP_RBUS_SUPPORT -DRTMP_RF_RW_SUPPORT -DMT_MAC -DRTMP_MAC_PCI -DRTMP_PCI_SUPPORT
EXTRA_CFLAGS += -DRTMP_FLASH_SUPPORT -DDMA_SCH_SUPPORT -DRTMP_EFUSE_SUPPORT

$(DRV_NAME)-objs += $(ap_objs) $(cmm_objs) $(asic_objs) $(chip_objs) $(rate_objs)\
                    $(spec_objs) $(func_objs) $(os_objs)

$(DRV_NAME)-objs += $(SRC_DIR)/common/eeprom.o\
					$(SRC_DIR)/common/ee_flash.o\
					$(SRC_DIR)/common/ee_efuse.o

$(DRV_NAME)-objs += $(SRC_DIR)/common/cmm_mac_pci.o
$(DRV_NAME)-objs += $(SRC_DIR)/common/cmm_data_pci.o

$(DRV_NAME)-objs += $(SRC_DIR)/os/linux/rt_pci_rbus.o\
                    $(SRC_DIR)/os/linux/rt_rbus_pci_drv.o\
                    $(SRC_DIR)/os/linux/rt_rbus_pci_util.o\
                    #$(SRC_DIR)/os/linux/rbus_main_dev.o

ifeq ($(CONFIG_ATE_SUPPORT),y)
$(DRV_NAME)-objs += $(SRC_DIR)/../ate/ate_agent.o\
                    $(SRC_DIR)/../ate/qa_agent.o\
                    $(SRC_DIR)/../ate/mt_mac/mt_ate.o
endif

###################
#  CFLAGS
##################
EXTRA_CFLAGS += -DAGGREGATION_SUPPORT -DPIGGYBACK_SUPPORT -DWMM_SUPPORT  -DLINUX \
               -Wall -Wstrict-prototypes -Wno-trigraphs -Wframe-larger-than=4096
#-DDBG_DIAGNOSE -DDBG_RX_MCS -DDBG_TX_MCS

EXTRA_CFLAGS += -DCONFIG_AP_SUPPORT -DSCAN_SUPPORT -DAP_SCAN_SUPPORT
EXTRA_CFLAGS += -DDOT11_N_SUPPORT -DDOT11N_DRAFT3 -DSTATS_COUNT_SUPPORT -DIAPP_SUPPORT -DDOT1X_SUPPORT
#EXTRA_CFLAGS += -DRALINK_ATE -DRALINK_QA -DCONFIG_RT2880_ATE_CMD_NEW
EXTRA_CFLAGS += -DCONFIG_RA_NAT_NONE
EXTRA_CFLAGS += -DIP_ASSEMBLY

MODULE_FLAGS=$(EXTRA_CFLAGS)
export MODULE_FLAGS
obj-m+=$(SRC_DIR)/tools/plug_in/

主要是3點:H頭文件路徑設置,通過宏控制哪些C文件參與編譯,以及通過-D傳入宏定義編譯源碼文件

整個移植過程其實就是參照這3點出發的;

頭文件路徑這個沒什麼好說的,就是一個相對路徑

通過宏控制哪些C文件參與編譯,其實就是Menuconfig的菜單顯示,選哪些不選哪些,openwrt中添加內核包的方式,這裏就不做介紹,這裏通過config.in的方式來配置包選項

if PACKAGE_kmod-mt7688

config MT7628_RT_FIRST_CARD
	int
	default 7628

config MT7628_MT_WIFI
	bool
	select MT7628_WIFI_BASIC_FUNC
	default y

config MT7628_MT_WIFI_PATH
		string
		depends on MT7628_MT_WIFI
		default "rlt_wifi"

menu "WiFi Generic Feature Options"

config MT7628_FIRST_IF_EEPROM_FLASH
	bool
	default y

config MT7628_RT_FIRST_CARD_EEPROM
		string
		default "flash"


config MT7628_SECOND_IF_EEPROM_FLASH
	bool
	default y

config MT7628_RT_SECOND_CARD_EEPROM
		string
		default "flash"
		
config MT7628_MULTI_INF_SUPPORT
		bool "MULTI INF SUPPORT"
		default n

config MT7628_WIFI_BASIC_FUNC
	bool "Basic Functions"
	select WIRELESS_EXT
	select WEXT_SPY
	select WEXT_PRIV

config MT7628_WIFI_WORK_QUEUE
	bool "Work Queue"
	default n

config MT7628_WIFI_SKB_RECYCLE
	bool "SKB Recycle(Linux)"
	default n


menu "WiFi Operation Modes"
config MT7628_WIFI_MODE_AP
		bool
		default y

config MT7628_MT_AP_SUPPORT
	bool #"Ralink RT2860 802.11n AP support"
	select WIRELESS_EXT
	select WEXT_SPY
	select WEXT_PRIV
	default y

config MT7628_WDS_SUPPORT
	bool "WDS"
	depends on MT7628_MT_AP_SUPPORT

config MT7628_MBSS_SUPPORT
	bool "MBSSID"
	depends on MT7628_MT_AP_SUPPORT
	default y

config MT7628_NEW_MBSSID_MODE
	bool "New MBSSID MODE"
	depends on MT7628_MT_AP_SUPPORT
	default y

config MT7628_ENHANCE_NEW_MBSSID_MODE
	bool "Enhanced MBSSID mode"
	depends on MT7628_NEW_MBSSID_MODE
	default y

config MT7628_APCLI_SUPPORT
	bool "AP-Client Support"
	depends on MT7628_MT_AP_SUPPORT

config MT7628_MAC_REPEATER_SUPPORT
	bool "MAC Repeater Support"
	depends on MT7628_MT_AP_SUPPORT
	depends on MT7628_APCLI_SUPPORT
	default y

config MT7628_APCLI_AUTO_BW_SUPPORT
	bool "apcli auto bw"
	depends on MT7628_MT_AP_SUPPORT
	depends on MT7628_APCLI_SUPPORT
	default n
	
config MT7628_SNIFFER_SUPPORT
	bool "SNIFFER"
	depends on MT7628_MT_AP_SUPPORT
	default n

endmenu	

endif

包名取作MT7688,配置項以MT7628開頭,這裏這麼做,主要爲了顯示與MTK源碼中Kconfig的區別,因此既然有區別,那麼在編譯時是肯定要做處理。

此config.in的配置選項,最終會在 .config 文件中以CONFIG_MT7628_XXXX=y的方式來體現,同時也被Makefile所使用。

openwrt中編譯一個包有兩個Makefile來控制,一個是包的Makefile,一個實際源碼編譯的Makefile(就是文章開頭的那一個)。

包的Makefile如下:

# All rights reserved.
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.

include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk

PKG_NAME:=mt7688
P4REV:=190329
PKG_VERSION:=p4rev-$(P4REV)
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tgz
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)

PKG_KCONFIG:= \
	MT_WIFI MT_WIFI_PATH FIRST_IF_EEPROM_PROM FIRST_IF_EEPROM_EFUSE \
	FIRST_IF_EEPROM_FLASH RT_FIRST_CARD_EEPROM RT_SECOND_CARD_EEPROM \
	MULTI_INF_SUPPORT WIFI_BASIC_FUNC WSC_INCLUDED WSC_V2_SUPPORT \
	DOT11N_DRAFT3 DOT11W_PMF_SUPPORT LLTD_SUPPORT QOS_DLS_SUPPORT \
	WAPI_SUPPORT IGMP_SNOOP_SUPPORT BLOCK_NET_IF RATE_ADAPTION \
	NEW_RATE_ADAPT_SUPPORT AGS_SUPPORT IDS_SUPPORT WIFI_WORKQUEUE \
	WIFI_SKB_RECYCLE LED_CONTROL_SUPPORT ATE_SUPPORT MEMORY_OPTIMIZATION 

PKG_CONFIG_DEPENDS:=$(foreach c, $(PKG_KCONFIG),$(if $(CONFIG_$c),CONFIG_$(c)))

include $(INCLUDE_DIR)/package.mk

TAR_CMD=$(HOST_TAR) -C $(1)/ $(TAR_OPTIONS)

define KernelPackage/mt7688
  TITLE:=MTK MT7688 wifi driver
  FILES:=$(PKG_BUILD_DIR)/build/mt7628.ko
  SUBMENU:=Wireless Drivers
  MENU:=1
  AUTOLOAD:=$(call AutoLoad,98,mt7628)
endef

define KernelPackage/mt7688/config
	source "$(SOURCE)/config.in"
endef

define Build/Compile
	$(MAKE) -C "$(LINUX_DIR)" V=1 \
		CROSS_COMPILE="$(TARGET_CROSS)" \
		ARCH="$(LINUX_KARCH)" \
		SUBDIRS="$(PKG_BUILD_DIR)/build/" \
		$(foreach c, $(PKG_KCONFIG),$(if $(CONFIG_MT7628_$c),CONFIG_$(c)=$(CONFIG_MT7628_$(c))))\
		modules
endef

define KernelPackage/mt7688/install
	$(INSTALL_DIR) $(1)/etc/wireless/mt7628/
	$(INSTALL_BIN) ./files/mt7628.dat $(1)/etc/wireless/mt7628/
endef

$(eval $(call KernelPackage,mt7688))

其常規的通用部分就不說了,特殊的一點在於$(CONFIG_MT7628_$c),CONFIG_$(c)=$(CONFIG_MT7628_$(c))))\

即把config.in的CONIG_MT7628_XXX=y 轉換爲CONFIG_XXX 再傳入供源碼編譯的Makefile,因爲源碼編譯的Makefile比較特殊,不懂的最好不要修改,搞不好就編譯不對,因此爲了保險,此處由config.bin去適配makefile中的一些選項。

但是有比較重要的一點在於,這些CONFIG_XXX不會參與源碼編譯,只會用於Makefile中使用,即控制哪些文件參與編譯或者定義哪些宏。真正在源碼中使用到的宏都是通過EXTRA_CFLAGS+=-Dxxx的方式傳入的

因此我們參照驅動編譯源碼所用的Makefile,提取CONFIG_XXX,即可形成config.in,然後可由menuconfig來控制編譯選項。

到此我們只是完成了一部分,僅僅是能夠控制編譯選項,並且只能編譯代碼而已。其實由於kernel的升級,以及openwrt與原始SDK的不同,需要修改源碼的部分實現。主要有以下幾個地方:

1. 文件系統讀取和寫入接口 以及部分頭文件

2. 中斷號

3. 配置參數文件路徑,比如/etc/wireless/mt7628/mt7628.dat

4. 增加MAC地址讀取和寫入函數,一般是從flash的factory分區讀取

至此,我們才完成了整個驅動的移植,但也僅僅只限於加載成功以及使用默認的參數。

如果需要修改wifi參數,需要添加/lib/wifi/ralink.sh等類似腳本,使用iwpriv來修改相關參數

甚至如果要兼容luci,需要給iwinfo增加私有驅動的接口,主要是SSID列表掃碼接口,還有iwpriv參數與802.11通用參數的轉換,有一個工具可用uci2dat

最後說一個‘big’ bug,V4.1.0.0支持搜所中文的SSID,但是應用獲取輸出結果時會crash

首先我懷疑是列表太多,存儲空間不夠,後來懷疑是驅動移植問題,某些編譯選項不對,但最最後一個一個命令的調試發現,是中文SSID的問題。

所有WIFI設備的SSID最大長度爲32個字符,但我們使用全英文字符時不會有問題,但是遇到中文時,MTK WIFI驅動會將其轉換爲0xaabb的方式,即一箇中文字變成2個字符,長度增加一倍,如下:

	CHAR		Ssid[MAX_LEN_OF_SSID*2 +1];
	RTMP_STRING SecurityStr[32] = {0};
	NDIS_802_11_ENCRYPTION_STATUS	ap_cipher = Ndis802_11EncryptionDisabled;
	NDIS_802_11_AUTHENTICATION_MODE	ap_auth_mode = Ndis802_11AuthModeOpen;
#ifdef AIRPLAY_SUPPORT	
	BOOLEAN isUniCodeSsid = FALSE;
#endif /* AIRPLAY_SUPPORT */	

		/*Channel*/
		sprintf(msg+strlen(msg),"%-4d", pBss->Channel);


		/*SSID*/
	NdisZeroMemory(Ssid, (MAX_LEN_OF_SSID*2 +1));
	if (RTMPCheckStrPrintAble((PCHAR)pBss->Ssid, pBss->SsidLen))
		NdisMoveMemory(Ssid, pBss->Ssid, pBss->SsidLen);
	else
	{
		INT idx = 0;

#ifdef AIRPLAY_SUPPORT		
		isUniCodeSsid = TRUE;
#endif /* AIRPLAY_SUPPORT */
		
		sprintf(Ssid, "0x");
		for (idx = 0; (idx < MAX_LEN_OF_SSID) && (idx < pBss->SsidLen); idx++)
			sprintf(Ssid + 2 + (idx*2), "%02X", (UCHAR)pBss->Ssid[idx]);
	}
		sprintf(msg+strlen(msg),"%-33s", Ssid);

具體爲:sprintf(Ssid + 2 + (idx*2), "%02X", (UCHAR)pBss->Ssid[idx]);

移植完成最後測試下來,速度和穩定性還不錯,比MT76要強很多

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章