零零碎碎的时间,折腾了好久,看了不知道多少帖子,教程,终于在香蕉派成功编译并加载了小度Wifi的驱动。其实也就是360Wifi,小米Wifi,腾讯Wifi等的驱动。因为它们基本都是mt7601u的芯片。好了,废话不多说,进入主题。

环境

硬件:香蕉派M1/BPI-M1 系统:bananian-1508 网卡:小度Wifi2(mt7601u芯片)

软件

  1. 编译环境 make等编译环境自然需要准备好。我之前安装了lnmp一键安装包,编译环境都自动给我装好了,所以具体我也不知道需要哪些组件。
  2. 内核头文件 首先在终端执行uname -a,看一下现在系统的内核版本。
    nono@pibox ~ % uname -a
    Linux pibox 3.4.108-bananian #2 SMP PREEMPT Thu Aug 13 06:08:25 UTC 2015 armv7l GNU/Linux
    
    然后用apt-get命令安装对应版本的内核头文件
    sudo apt-get install linux-headers-3.4.108-bananian
    
  3. 驱动源码 官方的驱动源码下载链接已经失效了,在网上循着文件名DPO_MT7601U_LinuxSTA_3.0.0.4_20130913.tar.bz2,找到了一个包,看样子未做太多修改。(这个包应该是新浪微盘下载的) 解压源码包
    tar -jxvf DPO_MT7601U_LinuxSTA_3.0.0.4_20130913.tar.bz2
    
  4. 编译前的准备 编辑源码包下的common/rtusb_dev_id.c
    #ifdef MT7601U
        {USB_DEVICE(0x148f,0x6370)}, /* Ralink 6370 */
        {USB_DEVICE(0x148f,0x7601)}, /* MT 6370 */
        {USB_DEVICE(0x2717,0x4106)}, /* Xiaomi Wifi */
    #endif /* MT7601U */
    
    把上面这段代码修改成下面这段,实际上就是添加上360Wifi、小度Wifi、小米Wifi等的设备ID
    #ifdef MT7601U
        {USB_DEVICE(0x148f,0x6370)}, /* Ralink 6370 */
        {USB_DEVICE(0x148f,0x7601)}, /* MT 6370 */
        {USB_DEVICE(0x2717,0x4106)}, /* Xiaomi Wifi */
        {USB_DEVICE(0x148f,0x760b)}, /* 360 Wifi */
        {USB_DEVICE(0x2a5f,0x1000)}, /* Tencent Wifi */
        {USB_DEVICE(0x2955,0x0001)}, /* XiaoDu Wifi */
        {USB_DEVICE(0x2955,0x1001)}, /* XiaoDu Wifi */
        {USB_DEVICE(0x2955,0x1003)}, /* NuoMi Wifi */
    #endif /* MT7601U */
    
    如果不确定你的设备ID在不在这上面,可以把你的usb无线网卡连上你的香蕉派,然后终端执行lsusb命令,根据显示的结果大概推测一下就能找到你的设备ID。如果不确定哪个是usb无线网卡的话,可以先拔掉usb无线网卡,执行lsusb命令,再插上usb无线网卡,然后执行lsusb命令。对比两次执行的结果,多出的那一行应该就是了。 比如下面Bus 001 Device 003: ID 2955:1001这一行,后面没有描述的,就是小度Wifi。万恶的百度啊,改了设备ID就算了,连描述信息也删了。
    nono@pibox ~ % lsusb
    Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
    Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
    Bus 003 Device 002: ID 0bda:8176 Realtek Semiconductor Corp. RTL8188CUS 802.11n WLAN Adapter
    Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
    Bus 001 Device 004: ID 0bc2:ab00 Seagate RSS LLC
    Bus 001 Device 003: ID 2955:1001
    Bus 001 Device 002: ID 1a40:0101 Terminus Technology Inc. 4-Port HUB
    Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
    
  5. 编译安装 回到源码主目录,执行make,不出意外的话应该能编译成功。 如果编译成功了,就可以执行sudo make install,把驱动模块安装到系统里去。 接着运行以下命令载入驱动
    sudo depmod
    sudo modprobe mt7601Usta
    
    我也不清楚驱动模块的生效要不要重启系统,然而事实上重启了也不能解决问题。请接着往下看。

Debug

重启系统前,我执行了一下sudo ifconfig -a,查看所有网络设备,然后并没有发现多出的设备。于是,我重启了系统,再次执行该命令,然并卵。

  1. 发现问题 于是我dmesg查看了一下开机信息,找到一点思路。
    [   14.243002] Freeing init memory: 228K
    [   15.309721] systemd-udevd[159]: starting version 215
    [   15.927477] rtusb init rt2870 --->
    [   15.938697] ===>rt2870_probe()!
    [   15.944676] --> RTMPAllocAdapterBlock
    [   15.952575] sd 1:0:0:0: Attached scsi generic sg0 type 0
    [   15.974653] === pAd = f02f9000, size = 851128 ===
    [   15.977963] --> RTMPAllocTxRxRingMemory
    [   15.988743] ERROR: 256 KiB atomic DMA coherent pool is too small!
    [   15.988752] Please increase it with coherent_pool= kernel parameter!
    [   16.022431] <-- ERROR in Alloc Bulk buffer for HTTxContext!
    [   16.025672] ---> RTMPFreeTxRxRingMemory
    [   16.030100] <--- RTMPFreeTxRxRingMemory
    [   16.037726] ERROR!!! Failed to allocate memory - TxRxRing
    [   16.066348] <-- RTMPAllocAdapterBlock, Status=3
    [   16.084313] rt2870: probe of 1-1.3:1.0 failed with error -1
    [   16.129699] usbcore: registered new interface driver rt2870
    
  2. 解决思路 搜索这些错误代码,顺藤摸瓜,找到了几篇相关的文章。知道了驱动加载失败的原因ERROR: 256 KiB atomic DMA coherent pool is too small!。对应的解决方法是在启动代码uEnv.txt中添加coherent_pool=2M。然而,bananian-1508的启动分区(第一个分区)下并没有uEnv.txt这个文件。仅有的类似的文件是boot.cmdboot.scr。查看了一下boot.cmd的具体内容,发现跟uEnv.txt的内容非常相似。(之前我有编辑过uEnv.txt这个文件。) 下面这是boot.cmd的具体内容
    #--------------------------------------------------------------------------------------------------------------------------------
    # Boot loader script to boot with different boot methods for old and new kernel
    # Credits: https://github.com/igorpecovnik - Thank you for this great script!
    #--------------------------------------------------------------------------------------------------------------------------------
    if load mmc 0:1 0x00000000 uImage-next
    then
    # mainline kernel >= 4.x
    #--------------------------------------------------------------------------------------------------------------------------------
    setenv bootargs console=ttyS0,115200 console=tty0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait
    load mmc 0:1 0x49000000 dtb/${fdtfile}
    load mmc 0:1 0x46000000 uImage-next
    bootm 0x46000000 - 0x49000000
    #--------------------------------------------------------------------------------------------------------------------------------
    else
    # sunxi 3.4.x
    #--------------------------------------------------------------------------------------------------------------------------------
    setenv bootargs console=ttyS0,115200 console=tty0 console=tty1 sunxi_g2d_mem_reserve=0 sunxi_ve_mem_reserve=0 hdmi.audio=EDID:0 disp.screen0_output_mode=EDID:1680x1050p60 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait
    setenv bootm_boot_mode sec
    load mmc 0:1 0x43000000 script.bin
    load mmc 0:1 0x48000000 uImage
    bootm 0x48000000
    #--------------------------------------------------------------------------------------------------------------------------------
    fi
    
  3. 编辑配置 boot.scr的内容与上面几乎完全相同,但是文件头部有一部分“乱码”。实际上boot.scr是由boot.cmd经过编译得到的。因此可以直接编辑boot.cmd而不可以编辑boot.scr。另外,编辑之前一定要备份文件。这都是我血的教训啊。 在boot.cmd中有两段关于启动参数的配置,保险起见,这两段我们都修改一下。找到setenv bootargs,在这行代码的最末尾,也就是在rootwait后面添加参数coherent_pool=2M。编辑后的代码如下所示
    #--------------------------------------------------------------------------------------------------------------------------------
    # Boot loader script to boot with different boot methods for old and new kernel
    # Credits: https://github.com/igorpecovnik - Thank you for this great script!
    #--------------------------------------------------------------------------------------------------------------------------------
    if load mmc 0:1 0x00000000 uImage-next
    then
    # mainline kernel >= 4.x
    #--------------------------------------------------------------------------------------------------------------------------------
    setenv bootargs console=ttyS0,115200 console=tty0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait coherent_pool=2M
    load mmc 0:1 0x49000000 dtb/${fdtfile}
    load mmc 0:1 0x46000000 uImage-next
    bootm 0x46000000 - 0x49000000
    #--------------------------------------------------------------------------------------------------------------------------------
    else
    # sunxi 3.4.x
    #--------------------------------------------------------------------------------------------------------------------------------
    setenv bootargs console=ttyS0,115200 console=tty0 console=tty1 sunxi_g2d_mem_reserve=0 sunxi_ve_mem_reserve=0 hdmi.audio=EDID:0 disp.screen0_output_mode=EDID:1680x1050p60 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait coherent_pool=2M
    setenv bootm_boot_mode sec
    load mmc 0:1 0x43000000 script.bin
    load mmc 0:1 0x48000000 uImage
    bootm 0x48000000
    #--------------------------------------------------------------------------------------------------------------------------------
    fi
    
  4. 生成配置 boot.cmd编辑完成,接下来就是要生成boot.scr文件。这里需要用到u-boot的工具mkimage,一般都可以直接安装软件源里的u-boot-tools软件包。或者可以下载u-boot的源代码自己编译。然后就可以用以下命令生成boot.scr了。当然,要在boot.cmd的目录下执行。
    mkimage -A arm -O linux -T script -C none -name 'mt7601usta_debug' -d boot.cmd boot.scr
    
  5. 重启生效 这两个文件都有了以后就可以把它们复制到启动分区里了。然后就可以重启了。这一步比较危险,所以要做好文件备份和恢复。 不出意外的话,重启后dmesg,可以看到以下信息
    [   14.181600] Freeing init memory: 228K
    [   15.276835] systemd-udevd[158]: starting version 215
    [   15.916705] rtusb init rt2870 --->
    [   15.918658] ===>rt2870_probe()!
    [   15.926758] --> RTMPAllocAdapterBlock
    [   15.931477] === pAd = f04b4000, size = 851128 ===
    [   15.943277] sd 1:0:0:0: Attached scsi generic sg0 type 0
    [   15.945815] --> RTMPAllocTxRxRingMemory
    [   15.951554] <-- RTMPAllocTxRxRingMemory, Status=0
    [   15.961370] <-- RTMPAllocAdapterBlock, Status=0
    [   15.962873] NumEndpoints=8
    [   15.965844] BULK IN MaxPacketSize = 512
    [   15.967630] EP address = 0x84
    [   15.970259] BULK IN MaxPacketSize = 512
    [   15.978693] EP address = 0x85
    [   15.981879] BULK OUT MaxPacketSize = 512
    [   15.984206] EP address = 0x 8
    [   15.987348] BULK OUT MaxPacketSize = 512
    [   15.989690] EP address = 0x 4
    [   15.992892] BULK OUT MaxPacketSize = 512
    [   15.995274] EP address = 0x 5
    [   16.000232] BULK OUT MaxPacketSize = 512
    [   16.007318] EP address = 0x 6
    [   16.014121] BULK OUT MaxPacketSize = 512
    [   16.020883] EP address = 0x 7
    [   16.039724] BULK OUT MaxPacketSize = 512
    [   16.051070] EP address = 0x 9
    [   16.058408] RTMP_COM_IoctlHandle():pAd->BulkOutEpAddr=0x8
    [   16.069071] RTMP_COM_IoctlHandle():pAd->BulkOutEpAddr=0x4
    [   16.078986] RTMP_COM_IoctlHandle():pAd->BulkOutEpAddr=0x5
    [   16.114469] RTMP_COM_IoctlHandle():pAd->BulkOutEpAddr=0x6
    [   16.136199] RTMP_COM_IoctlHandle():pAd->BulkOutEpAddr=0x7
    [   16.143712] RTMP_COM_IoctlHandle():pAd->BulkOutEpAddr=0x9
    [   16.146738] STA Driver version-3.0.0.3
    [   16.153618] -->MT7601_Init():
    [   16.158935] Chip specific bbpRegTbSize=0!
    [   16.177183] Chip VCO calibration mode = 0!
    [   16.178912] NVM is EFUSE
    [   16.181888] Efuse Size=0x1d [Range:1e0-1fc]
    [   16.185028] Endpoint(8) is for In-band Command
    [   16.187749] Endpoint(4) is for WMM0 AC0
    [   16.190283] Endpoint(5) is for WMM0 AC1
    [   16.192815] Endpoint(6) is for WMM0 AC2
    [   16.195369] Endpoint(7) is for WMM0 AC3
    [   16.197901] Endpoint(9) is for WMM1 AC0
    [   16.200433] Endpoint(84) is for Data-In
    [   16.203311] Endpoint(85) is for Command Rsp
    [   16.207599] Allocate a net device with private data size=0!
    [   16.210633] Allocate net device ops success!
    [   16.214475] The name of the new ra interface is ra0...
    [   16.216773] RtmpOSNetDevAttach()--->
    [   16.220685] <---RtmpOSNetDevAttach(), ret=0
    [   16.224509] <===rt2870_probe()!
    [   16.230934] usbcore: registered new interface driver rt2870
    
  6. 测试使用 然后可以sudo ifconfig -a,看看有没有ra0这个设备。如果有的话,恭喜你,成功了!这个设备就是你的小度Wifi。然后配置使用方法就跟设备wlan0一样咯。 执行以下命令可以使ra0设备生效
    sudo ip link set ra0 up
    
    再执行以下命令,可以扫描无线网络。如果有结果的话,一般来说就正常了。
    nono@pibox ~ % sudo iwlist ra0 scan
    ra0       Scan completed :
              Cell 01 - Address: 96:74:2A:AC:23:F3
                        Protocol:11b/g/n BW20
                        ESSID:"HHUCAN"
                        Mode:Managed
                        Frequency:2.412 GHz (Channel 1)
                        Quality=13/100  Signal level=-85 dBm  Noise level=-80 dBm
                        Encryption key:off
                        Bit Rates:65 Mb/s
              Cell 02 - Address: 96:74:2A:AC:25:D2
                        Protocol:11b/g/n BW20
                        ESSID:"HHUCAN"
                        Mode:Managed
                        Frequency:2.412 GHz (Channel 1)
                        Quality=94/100  Signal level=-53 dBm  Noise level=-92 dBm
                        Encryption key:off
                        Bit Rates:65 Mb/s
              Cell 03 - Address: 84:74:2A:AC:25:D2
                        Protocol:11b/g/n BW20
                        ESSID:"CMCC-EDU"
                        Mode:Managed
                        Frequency:2.412 GHz (Channel 1)
                        Quality=89/100  Signal level=-55 dBm  Noise level=-92 dBm
                        Encryption key:off
                        Bit Rates:65 Mb/s
    
    不知道是不是个bug。第一次扫描时只能扫描到公开网络,第二次扫描时才能显示全部的网络。 按照格式要求配置/etc/wpa_supplicant/wpa_supplicant.conf,然后执行以下命令测试连接无线网
    sudo wpa_supplicant -d -Dwext -ira0 -c/etc/wpa_supplicant/wpa_supplicant.conf
    

进阶

设备名称是ra0,肯定是有些不习惯。这是有办法修改的。 编辑驱动源码目录下的include/rtmp_def.h,把下面这段代码

#define INF_MAIN_DEV_NAME       "ra"
#define INF_MBSSID_DEV_NAME     "ra"

改成

#define INF_MAIN_DEV_NAME       "wlan"
#define INF_MBSSID_DEV_NAME     "wlan"

然后重新编译,安装,载入驱动就行了。 由于我的香蕉派上原来就有个usb无线网卡,所以新的设备名是wlan1。随之而来又有了网络配置的问题,重启后我的香蕉派连接不上网络了。幸好第一个usb无线网卡设置了热插拔,把两个网卡都拔掉,然后插上第一个usb无线网卡,就重新连了上来。 网络配置的问题,暂时还没有研究透。于是我使用的设备名依然是ra0,这样好像没有冲突,重启后两个网卡都能连上网络。

文件下载

参考文章