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什么样(由于太长,截取部分)
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传入宏定义编译源码文件
头文件路径这个没什么好说的,就是一个相对路径
通过宏控制哪些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(就是文章开头的那一个)。
# 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来控制编译选项。
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
首先我怀疑是列表太多,存储空间不够,后来怀疑是驱动移植问题,某些编译选项不对,但最最后一个一个命令的调试发现,是中文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要强很多