ZYBO開發板之mt7601u wifi驅動移植

Posted by Jason Wong on April 20, 2018

##1.移植wifi驅動需要考慮的問題。 對於ZYNQ開發板來說,移植WIFI驅動需要考慮PL工程的設計、設備樹、linux內核、開發板bootargs參數。 1)首先要檢查vivado工程裏的ZYNQ Processing System是否勾選了USB引腳,否則無法進行後面的移植操作。在這裏,PL工程的PS部分勾選的是USB0,如圖所示。

2)檢查設備樹是否有USB節點,節點對應的參數是否正確。正確是USB節點如下(這個節點是USB0)。

usb@e0002000 {
			compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";
			status = "okay";
			dr_mode = "host";
			clocks = <0x1 0x1c>;
			interrupt-parent = <0x4>;
			interrupts = <0x0 0x15 0x4>;
			reg = <0xe0002000 0x1000>;
			phy_type = "ulpi";
		};

可以參考XILINX的配置說明,裏面包含了linux內核和devicetree配置: http://www.wiki.xilinx.com/Zynq+Linux+USB+Device+Driver

3)配置linux內核。

Device Drivers
USB support
    <*> Support for Host-side USB
    <*> EHCI HCD (USB 2.0) support
    <*> USB Mass Storage support
    <*> ChipIdea Highspeed Dual Role Controller
    <*> ChipIdea host controller
        USB Physical Layer drivers --->
        <*> Generic ULPI Transceiver Driver

4)最後啓動開發板時使用lsusb命令檢查是否出現下面這些信息:

Bus 001 Device 002: ID 148f:7601

輸出這些信息時就表示成功識別了Ralink Technology, Corp. MT7601U Wireless Adapter ,對於移植WIFI驅動來說,基礎平臺的搭建已經沒有問題了。

##2.驅動移植 說明:因爲我的開發板使用的內核是4.9版本,驅動已經包含在linux kernel裏面,在編譯內核時進行相關的配置就可以了;需要注意的是內核編譯出來的wifi驅動不支持AP模式,AP模式的編譯工作在文章後面介紹。

>Networking support 
--- Wireless                                                     
      <*>   cfg80211 - wireless configuration API                        
     [ ]     nl80211 testmode command                               
     [ ]     enable developer warnings                              
     [ ]     cfg80211 certification onus                           
     [*]     enable powersave by default                            
     [ ]     use statically compiled regulatory rules database        
     [*]     cfg80211 wireless extensions compatibility                
      <*>   Generic IEEE 802.11 Networking Stack (mac80211)          
      [*]   Minstrel     
    [*]     Minstrel 802.11n support  
> Device Drivers > Network device support 
--- Wireless LAN 
     [*]   MediaTek devices                                        
      	<M>     MediaTek MT7601U (USB) support                           
     [*]   Ralink devices   
     <*>     Ralink driver support  --->
     		<*>   Ralink rt27xx/rt28xx/rt30xx (USB) support 

編譯linux

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -j2

編譯modules

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make modules

編譯出來的mt7601u.ko文件在drivers/net/wireless/mediatek/mt7601u下面

把mt7601u.ko復制到開發板備用。 在開發板上啓動linux,執行

insmod mt7601u.ko

在我的開發板上加載成功後顯示這些信息

usb 1-1: reset high-speed USB device number 2 using ci_hdrc                     
mt7601u 1-1:1.0: ASIC revision: 76010001 MAC revision: 76010500                 
mt7601u 1-1:1.0: EEPROM ver:0c fae:00                                           
usbcore: registered new interface driver mt7601u 

執行 ifconfig -a 命令會看到wlan0設備

當然,這是linux-4.9版本內置的mt7601u驅動,如果使用的版本較低如4.1以下的話就需要自己下載源碼另外編譯驅動了。推薦的源碼下載地址 https://github.com/kuba-moo/mt7601u

如果需要mt7601u.bin文件的話可以到這裏下載

##3.移植wireless-tools到開發板 1)首先下載wireless-tools源碼,下載地址在這裏: http://www.linuxfromscratch.org/blfs/view/stable/basicnet/wireless_tools.html

修改Makefile,主要是修改PREFIX, CC, AR, RANLIB這些參數,同時記得把# BUILD_STATIC = y的注釋去掉

##
## Please check the configurion parameters below
##

## Installation directory. By default, go in /usr/local.
## Distributions should probably use /, but they probably know better...
#修改處
ifndef PREFIX
  PREFIX = /home/huang/source/wireless/build/wireless-tools
endif

#修改處
## Compiler to use (modify this for cross compile).
CC = /opt/Xilinx/SDK/2017.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/arm-linux-gnueabihf-gcc
## Other tools you need to modify for cross compile (static lib only).
AR = /opt/Xilinx/SDK/2017.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/arm-linux-gnueabihf-ar
RANLIB = /opt/Xilinx/SDK/2017.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/arm-linux-gnueabihf-ranlib

## Uncomment this to build tools using static version of the library.
## Mostly useful for embedded platforms without ldd, or to create
#修改處
## a local version (non-root).
BUILD_STATIC = y

執行 make make install 在wireless-tools/sbin下的文件復制到開發板的/bin目錄下,並且在開發板/bin目錄下執行

chmod 777 iw*

注意:需要復制交叉編譯工具鏈的一些lib文件到開發板的/lib目錄下,否則移植的程式無法運行。

cp -v /opt/Xilinx/SDK/2017.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/arm-linux-gnueabihf/libc/lib/libc-2.3.2.so _install/lib
cp -v /opt/Xilinx/SDK/2017.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/arm-linux-gnueabihf/libc/lib/libc.* _install/lib
cp -v /opt/Xilinx/SDK/2017.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/arm-linux-gnueabihf/libc/lib/libm-2.3.2.so _install/lib
cp -v /opt/Xilinx/SDK/2017.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/arm-linux-gnueabihf/libc/lib/libm.* _install/lib
cp -v /opt/Xilinx/SDK/2017.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/arm-linux-gnueabihf/libc/lib/ld-* _install/lib
cp -v /opt/Xilinx/SDK/2017.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/arm-linux-gnueabihf/libc/lib/libthread_db* _install/lib

##4.配置開發板網路 1)配置wifi適配器,ip地址要和連接的wifi在同一個網域內,如我的wifi熱點地址是192.168.12.1,在開發板設置wlan0設備的地址爲192.168.12.12

ifconfig wlan0 192.168.12.12 netmask 255.255.255.0 up

2)設置默認網關

route add default gw 192.168.12.1

3)掃描wifi網路

iwlist wlan0 scan

掃描完成時顯示如下:

.....
 Cell 05 - Address: 90:94:E4:AA:C6:22                                  
                    Channel:9                                                   
                    Frequency:2.452 GHz (Channel 9)                             
                    Quality=57/70  Signal level=-53 dBm                         
                    Encryption key:off                                          
                    ESSID:"Debian"                                               
                    Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 6 Mb/s         
                              9 Mb/s; 12 Mb/s; 18 Mb/s                          
                    Bit Rates:24 Mb/s; 36 Mb/s; 48 Mb/s; 54 Mb/s                
                    Mode:Master                                                 
                    Extra:tsf=000005ea01e39533                                  
                    Extra: Last beacon: 60ms ago                                
                    IE: Unknown: 0005646C696E6B                                 
                    IE: Unknown: 010882848B960C121824                           
                    IE: Unknown: 030109                                         
                    IE: Unknown: 2A0100                                         
                    IE: Unknown: 32043048606C                                   
.....

4)連接wifi

iwconfig wlan0 essid "Debian"

連接成功後輸出信息

[root@huang:/]#iwconfig wlan0 essid "Debian"                                    
wlan0: authenticate with 74:e5:43:e7:3b:e4                                      
wlan0: send auth to 74:e5:43:e7:3b:e4 (try 1/3)                                 
[root@huang:/]#wlan0: authenticated                                             
mt7601u 1-1:1.0 wlan0: disabling HT as WMM/QoS is not supported by the AP       
mt7601u 1-1:1.0 wlan0: disabling VHT as WMM/QoS is not supported by the AP      
wlan0: associate with 74:e5:43:e7:3b:e4 (try 1/3)                               
wlan0: RX AssocResp from 74:e5:43:e7:3b:e4 (capab=0x401 status=0 aid=1)         
IPv6: ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready                        
wlan0: associated   

由於是測試用,連接的wifi沒有密碼;有密碼時,假設密碼是1234567890,需要這樣連接

iwconfig wlan0 essid "Debian" key s:1234-5678-90

即每4位爲一組,連接成功後ping一下wifi的地址

[root@huang:/]#ping 192.168.12.1                                                
PING 192.168.12.1 (192.168.12.1): 56 data bytes                                 
64 bytes from 192.168.12.1: seq=0 ttl=64 time=1.713 ms                          
64 bytes from 192.168.12.1: seq=1 ttl=64 time=1.588 ms                          
64 bytes from 192.168.12.1: seq=1 ttl=64 time=1.824 ms (DUP!)                   
64 bytes from 192.168.12.1: seq=2 ttl=64 time=1.523 ms                          
64 bytes from 192.168.12.1: seq=2 ttl=64 time=2.260 ms (DUP!)                   
^C                                                                              
--- 192.168.12.1 ping statistics ---                                            
3 packets transmitted, 3 packets received, 2 duplicates, 0% packet loss         
round-trip min/avg/max = 1.523/1.781/2.260 ms     

測試一下是否可以連接外網

[root@huang:/]#ping 1.0.0.1
PING 1.0.0.1 (1.0.0.1): 56 data bytes
64 bytes from 1.0.0.1: seq=0 ttl=47 time=164.691 ms
64 bytes from 1.0.0.1: seq=0 ttl=47 time=165.049 ms (DUP!)
64 bytes from 1.0.0.1: seq=1 ttl=47 time=166.982 ms
64 bytes from 1.0.0.1: seq=1 ttl=47 time=167.340 ms (DUP!)
^C
--- 1.0.0.1 ping statistics ---
2 packets transmitted, 2 packets received, 2 duplicates, 0% packet loss
round-trip min/avg/max = 164.691/166.015/167.340 ms

但是如果沒有設置DNS伺服器時,ping域名會ping不通,所以要設置DNS伺服器地址。 1)在/etc/下建立resolv.conf文件,當然也可以從宿主機直接復制過來用。nano /etc/resolv.conf 並在裏面添加:

nameserver 192.168.12.0
nameserver 37.235.1.177

注意:之所以添加192.168.12.0,是因爲執行route命令時看到:

[root@huang:/]#route                                                           
Kernel IP routing table                                                        
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface  
default         192.168.12.1    0.0.0.0         UG    0      0        0 wlan0  
default         192.168.65.1    0.0.0.0         UG    0      0        0 eth0   
192.168.12.0    *               255.255.255.0   U     0      0        0 wlan0  
192.168.65.0    *               255.255.255.0   U     0      0        0 eth0  

wifi相當與一個DNS服務器,所以要添加進來,否則也不能解析域名。

2)從交叉編譯工具鏈添加libnss*文件到根文件系統/lib目錄下

cp -v /opt/Xilinx/SDK/2017.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/arm-linux-gnueabihf/libc/lib/*nss* _install/lib

重新啓動開發板後就可以正確解析外網域名了。

[root@huang:/]#ping www.bbc.com                                                
PING www.bbc.com (212.58.246.55): 56 data bytes                                
64 bytes from 212.58.246.55: seq=0 ttl=45 time=335.045 ms                      
64 bytes from 212.58.246.55: seq=1 ttl=45 time=334.227 ms                      
64 bytes from 212.58.246.55: seq=1 ttl=45 time=335.225 ms (DUP!)               
64 bytes from 212.58.246.55: seq=2 ttl=45 time=335.796 ms                      
                                                                       
--- www.bbc.com ping statistics ---                                            
4 packets transmitted, 3 packets received, 1 duplicates, 25% packet loss       
round-trip min/avg/max = 334.227/335.073/335.796 ms   

試一下ipv6

[root@huang:/]#ping6 google.com                                                
PING google.com (2404:6800:4012:1::200e): 56 data bytes                        
64 bytes from 2404:6800:4012:1::200e: seq=0 ttl=40 time=115.892 ms             
64 bytes from 2404:6800:4012:1::200e: seq=1 ttl=40 time=133.562 ms             
64 bytes from 2404:6800:4012:1::200e: seq=2 ttl=40 time=153.433 ms             
64 bytes from 2404:6800:4012:1::200e: seq=3 ttl=40 time=171.441 ms             
                                                                        
--- google.com ping statistics ---                                             
4 packets transmitted, 4 packets received, 0% packet loss                      
round-trip min/avg/max = 115.892/143.582/171.441 ms     

也成功了,至此開發板的網絡配置完成。

##5.配置成AP模式

mt7601的AP模式用另外的驅動,上面配置的是STA模式,可以從linux內核直接編譯;但是AP模式要另外下載編譯。mt7601的AP驅動可以從這裏下載:git clone https://github.com/tanaka1892/mt7601u-ap

編譯成功後驅動在mt7601u-ap/os/linux/mt7601Uap.ko,再在/etc下建立wifi/RT2870AP文件夾,把RT2870AP.txt文件複製到此文件夾內。

mkdir -p /etc/wifi/RT2870AP
cp -v RT2870AP.txt /etc/wifi/RT2870AP/

若出現編譯錯誤,如:

/home/huang/xilinx/driver/wifi/mt7601u-ap/os/linux/../../ap/ap_data.c:5213:30:error: passing argument 2 of ‘hex_dump’ from incompatible pointer type [-Werror=incompatible-pointer-types]
  hex_dump("DataFrameHeader", pHeader, 36);

則需要修改linux-xlnx-master根目錄下的Makefile文件,在817行處修改

把
816 # enforce correct pointer usage
817 KBUILD_CFLAGS   += $(call cc-option,-Werror=incompatible-pointer-types)
修改爲
816 # enforce correct pointer usage
817 KBUILD_CFLAGS   += $(call cc-option,-Wno-error=incompatible-pointer-types)

在我這裏,編譯驅動並且加載成功了,但是後面啓動無線適配器時卻工作不正常,即開啓AP模式後,使用iwconfig查看時,生成了很多個interface,從ra0 - ra15,essid是HT_AP0,HT_AP1…..然而在手機wifi連接界面上只看到了HT_AP0,連接會顯示失敗。 後面我在這個博客 看到了解決辦法,我遇到的問題是驅動沒有成功讀取配置文件,這時候驅動就會使用默認的配置。這時可以修改mt7601u-ap/os/linux/rt_linux.c

int RtmpOSFileRead(RTMP_OS_FD osfd, char *pDataPtr, int readLen)
{
    DBGPRINT(RT_DEBUG_ERROR, ("add: %p %p\n", osfd->f_op, osfd->f_op->read));
        /* The object must have a read method */
        if (osfd->f_op /*&& osfd->f_op->read*/) {
                //return osfd->f_op->read(osfd, pDataPtr, readLen, &osfd->f_pos);
                return vfs_read(osfd, pDataPtr, readLen, &osfd->f_pos);
        } else {
                DBGPRINT(RT_DEBUG_ERROR, ("no file read method\n"));
                return -1;
        }
}

修改保存,重新編譯。在啓動開發板之前,需要在uboot界面修改bootargs參數,比如我的開發板bootargs參數這樣設置

setenv bootargs 'root=/dev/raw rw cma=15M coherent_pool=2M  init=/linuxrc'

這裏的啓動方式是q-spi啓動,如果是其他啓動方式則要進行相應修改;注意coherent_pool=2M參數必須要有,否則驅動加載會出錯:

rt2870: probe of 1-1:1.0 failed with error -1

加載成功後使用iwconfig命令可以查看到以下信息。

[root@huang:/home]#iwconfig                                                     
lo        no wireless extensions.                                               
                                                                                
sit0      no wireless extensions.                                               
                                                                                
eth0      no wireless extensions.                                               
                                                                                
ra0       IEEE 802.11bgn  ESSID:"arm-linux-AP"                                  
          Mode:Master  Channel:11  Access Point: 28:F3:66:71:88:81              
          Bit Rate=72 Mb/s  

使用手機連接成功,AP熱點名是arm-linux-AP。注意:目前僅僅是實現了手機和開發板的局域網通信,由於在AP模式下沒有配置DNS和ip轉發規則,所以並不能訪問外部網路,這個待日後完善。

測試開發板與手機是否連接成功

[root@huang:/home]#ping 192.168.12.104                                          
PING 192.168.12.104 (192.168.12.104): 56 data bytes                             
64 bytes from 192.168.12.104: seq=0 ttl=64 time=13.620 ms                       
64 bytes from 192.168.12.104: seq=1 ttl=64 time=232.762 ms                      
64 bytes from 192.168.12.104: seq=2 ttl=64 time=5.873 ms                        
64 bytes from 192.168.12.104: seq=3 ttl=64 time=5.972 ms                        
^C                                                                              
--- 192.168.12.104 ping statistics ---                                          
4 packets transmitted, 4 packets received, 0% packet loss                       
round-trip min/avg/max = 5.873/64.556/232.762 ms