移植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要强很多

 

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