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要強很多