归档时间:三月, 2012

3G modem在linux上的移植

三 31 2012 由 创建在标签 开发

3G模块调试

第三代移动通信技术(3rd-generation,3G),是指支持高速数据传输的蜂窝移动通讯技术。3G服务能够同时传送声音及数据信息,速率一般在几百kbps以上。目前3G存在四种标准:CDMA2000,WCDMA,TD-SCDMA,WiMAX。

1简介

现在市场上的3G模块大部分都是zero CD模式,只能识别成CD-ROM,在这个虚拟的光驱中提供驱动,但是大部分厂商只会提供Windows驱动,少部分厂商提供Linux驱动(大部分厂商都是通过自己的工具或者通过udev来转换modem的模式,而嵌入式系统一般使用mdev),没有厂商提供嵌入式Linux驱动,对于做嵌入式Linux的人来说就要自己动手了。因而不能识别成我们所需要的串口设备,这样就没有办法去享受移动网络所带来的便利,也就没有办法完成任务了。网上有很多方法来让设备变成串口设备,所以让3G modem上网的主要工作就是将存储设备转换成串口设备。
USB modem转换成串口设备的方法主要有以下几种方法。

1.1eject命令

就是讲CD-ROM弹出,这个命令需要设备的支持,网上有很多人用这种方法来做,但是有很大一部分人来做,如果你买的设备支持,那恭喜你,可以不用看后面的内容了。

1.2修改通用设备将对应的设备忽略

文件drivers/usb/storage/unusual_devs.h中可以通过宏忽略我们的设备为通用设备,我们通过lsusb或者在windows设备管理器中可以查到设备的vendorID和productID,在文件中添加如下代码即可。

UNUSUAL_DEV(  vendorID, productID, 0x0000, 0x0000,
                "AzureWave",
                "AzureWave CDROM USB Device",
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_IGNORE_DEVICE ),

我使用的设备在这样修改后可以识别成一个ttyUSB0,没有测试那个串口是否可以直接发送AT命令,但是为了保险起见,还是想办法将其识别成多个串口设备。很多网上的资料都说要识别成多个串口,我猜可能是单个串口会影响到网速(个人猜测,没有验证)。

1.3通过usb_modeswitch切换modem的运行模式

我在这个过程中走了很多弯路,主要花在这个抓usb传输消息的过程,然后测试不同的消息发到USB modem那边看是否有反应,能否识别成多个串口。反复测试无果,只能想其他办法。

抓包是通过usbsniffer工具在windows下做的,因为一般的设备都提供了windows的驱动,在windows下可以获得驱动是如何让设备转换zeroCD模式的,如果知道了驱动发送的消息,我们在linux下面通过工具发送同样的消息就可以使设备安装我们的意愿工作了。

然而事情往往没有我们想象中的那么单纯,有了抓包这一步,就需要去区分哪些有用消息哪些是无效的消息,而抓包的过程中会产生很多报文,通过sh脚本和windows下自己写的工具来将数据提取出来(代码写得太挫,只为了提取数据)。通过TTerm的脚本批量发送获取的消息。

本以为到此结束,谁曾想到这只是一个开始,大量的数据中没有找到我要数据,那个伤心呐~~一时之间陷入困境,开始看USB子系统相关的知识。

功夫不负有心人,结合厂商提供的udev规则,发现我们的设备是工作在第二配置下,而在识别设备的时候都是直接使用的配置一。只要有工具能够修改设备的配置就可以了,本打算自己动手写一个,后来看usb_modeswitch代码的时候发现它是可以完成这个工作的,本打算只用它来发消息的,没想到它还能修改配置模式,可谓是转了一圈又回到了原点。这样修改配置后,设备就可以识别成我们想的串口了,一下子转换成12个ttyUSB,真是幸福来得太快了,但是这样也不好,需要区分哪些是可以发送AT命令的串口,只要做些区分就可以安装我们的意愿来工作了,可以在proc文件系统中看USB设备各个接口的工作模式,找到对应的串口就可以直接发送AT命令了。

1.4通过工具在Windows下禁用设备的zero CD模式

这个方法就是通过工具对设备进行操作,让设备在识别的时候就只能识别出串口设备,具体的机制不太明白,有点像软改。那样插上设备就可以直接识别出串口设备了。

1.5通过SYS文件系统

这个方法是我在读USB子系统的内核源码发现的,就是通过SYS文件系统提供的方法来实现USB设备配置的更改,与USB_modeswitch工具的原理是一样的,只是一个通过工具来做,一个是通过内核提供的文件系统来做,原理是相通的。

1.6几种方法的比较

第四种方法简单,但是并不建议使用,所以我在捣腾的过程中直接忽略这种方法,毕竟一个产品如果量产,我们要去修改每一个3G modem,那样工作量就太大了。还是比较推荐使用usb_modeswitch工具来修改设备的配置,这样最稳定,也不会留下任何后遗症;第二种方法其实并不可取,因为我们只是不识别成串口了,其他接口同样没有被识别出来,我虽然没有尝试就用一个串口来进行拨号,但是那样设备并没有真正工作在modem模式,不能叫设备正常运行;如果能够拨号成功,也不能算错或者有问题,最糟糕的就应该是识别出来的不是AT命令对应的tty口,那就让人郁闷了,拨号的时候不能拨通。

有了第五种方法后,usb_modeswitch工具似乎就可以不用了,但是这个只适用于USB设备是采用的多个配置方式来实现设备的,如果像华为那样通过消息来改变设备的工作模式的话,此方法并不可取,必须通过工具来实现运行模式的切换。

2内核配置

Device Drivers  --->
  [*] USB support  --->
       USB Serial Converter support  --->
      [*]   USB Generic Serial Driver
         USB driver for GSM and CDMA modems
  [*] Network device support  --->
          PPP (point-to-point protocol) support
       [*]     PPP multilink support (EXPERIMENTAL)
       [*]     PPP filtering
            PPP support for async serial ports
            PPP support for sync tty ports
            PPP Deflate compression
            PPP over Ethernet (EXPERIMENTAL)

2.1修改option.c文件

让option能够支持我们的模块。

2.2安装模块

/ # insmod /lib/modules/2.6.28/usbserial.ko
/ # insmod /lib/modules/2.6.28/option.ko

3 USB工具

俗话说:“工欲善其事必先利其器”,有好的工具就能够带来很高的效率。下面是我在测试3G模块成功过程中所用到的工具。可以根据自己的需要选用恰当的工具。

3.1 usbsniffer

windows下的USB抓包工具,可以监听usb口的数据传输,分析USB数据包。有很多工具可以使用,需要的可以在网上搜一下。我用的是SniffUsb。

3.2 libusb

其实这只是一个usb库,它不提供任何功能,但是下面的三个工具都会使用到这个库,所以在USB modem的调试过程中起着至关重要的作用。我们也可以通过这个库来写适合自己的小工具,USB库已经把与内核通信的接口封装好了,使用起来比较方便。写自己工具的适合可以适当参考usb_modeswitch工具的源码,那个里面包含了自动识别设备及接口的代码,以及消息的发送方法,有较大的参考意义。

3.2.1 交叉编译

[root@localhost] CC=/opt/EmbedSky/4.3.3/bin/arm-linux-gcc \
			     CXX=/opt/EmbedSky/4.3.3/bin/arm-linux-g++\
			     ./configure --build=i686-linux \
                                    --host=arm-linux \
			     --target=arm-linux \
			     --prefix=/home/ driver/3g/libusb-0.1.12/_install
[root@localhost] make
[root@localhost] make install

3.3 usb_modeswitch

切换多重USB设备运行模式的转换工具。现在一些新的USB 设备(特别是一些高速 WAN 设备,很贵的那种)都有MS Windows的驱动程序,当第一次插入机子的时候,它们处于闪存模式,并从中提取和安装驱动。在驱动安装完毕之后,驱动马上转换模式,储存设备消失(基本上都是这样的),然后一个新的设备(比如一个USB modem)出现。

此工具在网上有现成的配置文件可以下载,如果你的设备包含在其中的话,那就恭喜你能够省略很多繁琐的步骤去做抓包工作了,也可以少走很多弯路。

3.3.1 交叉编译

[root@localhost] CC=arm-none-linux-gnueabi-gcc \
                 CXX=arm-none-linux-gnueabi-g++ \
                 LD=arm-none-linux-gnueabi-ld \
                 CFLAGS="-I/home/driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                 CPPFLAGS="-g -I/home/driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                 CXXFLAGS="-g -I/home/driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                   ./configure --prefix=/home/driver/3g/libusb-0.1.12/_install \
                   --host=arm-linux\
                   --target=arm-linux
[root@localhost] make
[root@localhost] make install

3.4 lsusb

lsusb是一个学习USB驱动开发,认识USB设备的助手,它用于查询usb设备的信息,它依赖于虚拟文件中proc系统,在使用时需要配置内核。

3.4.1 交叉编译

[root@localhost] CC=arm-none-linux-gnueabi-gcc \
                 CXX=arm-none-linux-gnueabi-g++ \
                 LD=arm-none-linux-gnueabi-ld \
                 CFLAGS="-I/home/ driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                 CPPFLAGS="-g -I/home /driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                 CXXFLAGS="-g -I/home/ driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                   ./configure --prefix=/home/ driver/3g/libusb-0.1.12/_install \
                   --host=arm-linux\
                   --target=arm-linux
[root@localhost] make
[root@localhost] make install

3.5 ppp

智能拨号工具,其他拨号工具也会依赖此工具,如wvdial。拨号使用到两个可执行程序pppd和chat,有了这两个工具只要借助脚本就可以是modem拨号上网了。

这个工具的交叉编译也不是很难,只要修改一下makefile,然后直接make就可以了。

3.6 wvdial

自动拨号工具,通过wvdialconf工具可以测试接口支持的速率并自动生成配置文件,只需要改少量的配置就可以拨号上网。

我也没有交叉编译过此工具,只是在pc上用它生成过配置文件,并验证能否上网,在嵌入式设备上并没有使用它,因为开发板上的资源太紧张了。

3.7 ppp和wvdial比较

上两种方式各有自己的优缺点,第一种方式智能稳定,他不需要chat程序,使用集成的wvdial工具包直接连接ISP,安全稳定,可以断线自动重拨。第二方式,使用chat程序,但是很多的参数需要自己去配置,虽然比较灵活,但是如果遇到了拨号错误以后,你若不清ppp协议拨号实现的具体机制和每个参数的含义,你就会很吃力,也许运气好的时候,你运行的环境正好和本地的移动isp配置吻合,恭喜你能上网了,但是你遗憾的是没有学到东西,想了解 ppp机制的朋友,可以试试第2种方式,在了解大体了解ppp协议的前提下,观察思考/var/log/messages中的信息。

3.8 其他

minicom是linux下一款比较方便的串口助手,类似于Windows下的超级终端,功能比较强大可以自己使用的时候尝尝鲜。

3.8.1 ncurses-5.5

minicom的依赖库。

[root@localhost]# mkdir install
[root@localhost]# ./configure --build=i686-linux --host=arm-linux --prefix=/home/minicom/ncurses-5.5/install
[root@localhost]# make&&make install

3.8.2 minicom-2.1

minicom工具的编译。

[root@localhost]# mkdir install
[root@localhost]# ./configure --build=i686-linux --host=arm-linux --prefix=/ home /minicom/minicom-2.1/install/ CPPFLAGS="-I / home /minicom/ncurses-5.5/install/include/ncurses" LDFLAGS="-L / home /minicom/ncurses-5.5/install/lib"

3.8.3 minicom使用

至此工具已经编译完成,剩下的工作就是拷贝到开发板上去运行我们交叉编译的程序,不要以为工作已经全部完成,还有一步需要我们去做。就是配置minicom运行的环境变量。

如果没有配置终端信息的话,运行时会提示错误,需要将lib目录下的tesrminfo的v文件夹中的终端信息拷贝到文件系统中,并导出环境变量,这样在开发板上才能正确运行。

cp -r /lib/terminfo/v $rootfs/usr/share/terminfo
export TERMINFO=/usr/share/terminfo

4 热插拔脚本

开始尝试直接在hotplug文件中直接执行usb_modeswitch程序,但是在添加USB设备的阶段还是早了一点,于是就在mdev.conf文件中添加执行脚本。但是下面这段代码可以用来动态添加和删除模块。

SUBACTION="$SUBSYSTEM.$ACTION"
if [ "$SUBACTION" = "usb-serial.add" ] ; then
    SUBINFO=${PRODUCT:0:8}
    echo $SUBINFO>>/var/test
    if [ "$SUBINFO" = "4cc/231f" ] ; then
      /bin/usb_modeswitch -v 0x04cc -p 0x231f -u 2
      echo "testtttt">>/var/test
    fi
fi

5 拨号

设备识别出来后,下一步要做的工作就是拨号上网,其中内核中关于PPP的配置一定要配置上,否则拨号会失败。

5.1 运营商设置

不同的运营商会使用不同的拨号参数,虽然设备是一个,但是需要根据运营商来设置我们拨号相关的参数。而拨号的脚本基本相同,但是不同设备间可能会有少许差异,不同的设备可以根据实际来作简单调整。

5.1.1 电信3G设置

Dail number : #777
User name : card
Password : card

5.1.2 中国联通3G设置

APN:3gnet
Access number:*99#  (拨号号蚂)
User name: uninet
Password:空

5.1.3 中国移动 3G 设置

APN: cmnet
Access number 拨号号码: *99***1#
User name (账号) :空
Password (密码)  : 空

5.2 自动拨号

pppd connect 'chat  -v -s -r "/var/report" -f "/etc/ppp/ppp-on-dialer"' /dev/ttyUSB0 115200 mru 1280 mtu 1280 nodetach debug dump defaultroute usepeerdns novj novjccomp noipdefault ipcp-accept-remote connect-delay 5000 linkname ppp0
ABORT   BUSY
ABORT   'NO CARRIER'
ABORT   ERROR
REPORT  CONNECT
TIMEOUT 10
""      "AT&F"
OK      "ATE1"
OK      'AT+CGDCONT=1,"IP","3gnet"'
SAY     "Calling UMTS/GPRS"
TIMEOUT 30
OK      "ATD*99#"
CONNECT ' '

6 UI需求

拨号号码

apn
username
password

7 总结

还没有完全整理完毕,后续会继续补充。

附录:

1. usb_modeswitch网站(http://www.draisberghof.de/usb_modeswitch);
2. SniffUSB(http://www.pcausa.com/Utilities/UsbSnoop/default.htm);
3.

一条评论

ath9k_htc使用compatwireless在嵌入式linux上的使用

三 02 2012 由 创建在标签 开发

最近忙一个项目的无线模块,使用的是ath9k_htc这个wifi模块,由于官方没有提供驱动源码,只能使用无线兼容包。其实所有的驱动在高版本的内核中都已经包含,如果开发环境允许,可以使用高版本的内核,也许就不会遇到那么多的问题了。下面就言归正传,说说我是如何在2.6.28的内核上移植无线驱动的。

开发环境

内核版本:2.6.28

交叉编译器:gcc version 4.4.0 (Faraday C/C++ Compiler Release 20100325)

compatwireless:2.6(日期是2012-02-15)

firmware:1.3

wireless-tool:29

iw(配置ap模式,并没有实际测试)

配置内核

[*] Networking support  --->
    [*]   Wireless  --->
        [*]   Wireless extensions
        [*]     Wireless extensions sysfs files

-*- Cryptographic API  --->
    {M}   Cryptographic algorithm manager
       ARC4 cipher algorithm

配置内核使内核支持无线,由于802.11需要用到一些加密算法,所以需要把加密模块编译成模块,由于开始没有考虑加密,所以无线在连接的时候总是连不上,最终不得不在代码中寻找问题,后面我也会详细来说。

编译compatwireless

# 配置驱动类型
./scripts/driver-select ath9k_htc
# 编译驱动
make KLIB=//linux-2.6.28 KLIB_BUILD=/linux-2.6.28

这使ath9k_htc驱动的主体部分,它需要读取内核配置文件.conf,然后根据内核的配置来决定编译哪些模块。编译的时候会遇到很多问题,都可以根据它的提示来解决。主要是trace.h包含的一些调试函数,基本上所有的错误都是由于这个头文件里的函数造成的。我的处理办法就是把他们全部注释掉,但是这样就不能跟踪代码了。其实我们使用这个驱动也没有必要来跟踪代码,毕竟我们对802.11协议还不是十分了解,让我们这些外行跟踪内部的东西那就不敢想象其中的工作量了。

编写驱动加载脚本

# 兼容包及802.11驱动
insmod /lib/modules/2.6.28/compat.ko
insmod /lib/modules/2.6.28/compat_firmware_class.ko
insmod /lib/modules/2.6.28/rfkill_backport.ko
insmod /lib/modules/2.6.28/cfg80211.ko
insmod /lib/modules/2.6.28/mac80211.ko
# ath9k_htc驱动
insmod /lib/modules/2.6.28/ath.ko
insmod /lib/modules/2.6.28/ath9k_hw.ko
insmod /lib/modules/2.6.28/ath9k_common.ko
insmod /lib/modules/2.6.28/ath9k.ko
insmod /lib/modules/2.6.28/ath9k_htc.ko
# 加密模块
insmod /lib/modules/2.6.28/crypto_algapi.ko
insmod /lib/modules/2.6.28/arc4.ko

驱动编译完成后,先手动加载,发现驱动的加载有先后顺序,而且每次开机启动都要手动加载,那是相当的麻烦,所以就写了一个加载wifi驱动的脚本,开机后自动运行就可以了。主要是保证他们的加载先后顺序。

热插拔自动启动设备

#!/bin/sh

#do something that mdev has to do
/sbin/mdev $1

EVENT="$SUBSYSTEM.$INTERFACE.$ACTION";

if [ "$EVENT" = "net.wlan0.add" ] ; then
    iwconfig wlan0 essid "ap01"
    iwconfig wlan0 key 11111111111111111111111111
    echo "The wlan0 is created!">> /var/log
    ifconfig wlan0 up
# mdev 貌似不能发出linkup的热插拔时间,对此不太了解,所以在启动后就直接配置
#elif [ "$EVENT" = "net.wlan0.linkup" ] ; then
    ifconfig wlan0 192.168.88.188 netmask 255.255.255.0
    route add default gw 192.168.88.254
    echo "The wlan0 is up!">> /var/log
fi

可能显得没有很大的必要,因为设备一旦启动了,一般不会无缘无故把wifi设备拔掉,只要开机启动的时候做好就可以了,但是有了热插拔还有另一个好处,那就是自动配置设备,并启动设备。上面的配置也很简单,就是检测到无线wlan0插入后自动启动无线并配置ip地址,也可以根据实际应用开启相关的网络应用程序,保证对网络相关的程序能够正常执行。

遇到的问题及解决方案

wep不能认证

开始觉得很奇怪,为什么设备已经被识别了,而且能够正常工作,为什么加密后就不能连接ap,而是用open方式可以连接上ap。所就觉得不是驱动的问题,因为驱动有问题的话open方式的ap也就连接不上了,所以应该是加密或者配置的部分有问题。开始就在看compatwireless和wireless-tool的代码,代码实在是太庞大,想发现问题也没有那么容易,而且也没发现配置有问题,密码应该是配置下去了。

只有自己加一点调试信息,然后根据调试信息来定位,后来发现代码根本就没有走到认证的地方,无奈只能从驱动的初始化和wep加密相关的地方入手,就在初始化的过程中加了一些调试信息。同时修改内核,在内核配置的时候发现配置了内核中802.11协议栈的时候,发现协议栈对加密模块有依赖,而我在运行驱动的时候并没有加载加密的驱动,后来又跟踪到如下代码,发现用到了arc4算法,遂配置内核的加密模块,编译加载之,发现错误的调试信息就没有打印出来,同时也能上线了~~

int ieee80211_wep_init (struct ieee80211_local *local)
{
    /* start WEP IV from a random value */
    get_random_bytes (&local->wep_iv, WEP_IV_LEN);
    // 加载arc4加密模块
    local->wep_tx_tfm = crypto_alloc_cipher ("arc4", 0, CRYPTO_ALG_ASYNC);
    if (IS_ERR (local->wep_tx_tfm))
    {
        local->wep_rx_tfm = ERR_PTR (-EINVAL);
        return PTR_ERR (local->wep_tx_tfm);
    }

    local->wep_rx_tfm = crypto_alloc_cipher ("arc4", 0, CRYPTO_ALG_ASYNC);
    if (IS_ERR (local->wep_rx_tfm))
    {
        crypto_free_cipher (local->wep_tx_tfm);
        local->wep_tx_tfm = ERR_PTR (-EINVAL);
        return PTR_ERR (local->wep_rx_tfm);
    }

    return 0;
}

其实很难让人怀疑到是那个地方的错误,因为一般如果说某个函数不存在,在运行的时候会报错,而这个通过了一个接口封装,将算法的提取放到封装的函数接口中去了,而且这个接口特别友好,不会让你的程序在运行运行出错,只会告诉你一个简单的错误码。所以觉得有的时候太友好了导致的错误更让人头疼。

热插拔脚本不能执行

在/sbin目录下创建一个文件名为hotplug的shell脚本,在里面添加echo语句,但是前台没有打印,就直接判断不能执行热插拔的脚本。但是反复测试后发现即使用mdev来做也不会打印信息(有师兄说有时候会打印出echo输出的信息),但是其实它是在后台执行了的,只是没有表现出来而已。可以把打印出来的消息输入文件,然后在文件中查看,这样就可以确定是否真正运行了。

注意:需要注意的是hotplug可执行的脚本在第一行一定要加上:#!/bin/sh,否则不能执行。

ath9k_htc找不到firmware

这个问题我也不能完全确定,但是在两种情况下是不会发生的。第一:将mdev指定为/proc/sys/kernel/hotplug的执行程序;第二:在/sbin目录下添加上面写道hotplug脚本,而且需要添加:/sbin/mdev $1,如果不加也会出现错误。

所以就猜测是由于/sbin目录下不存在hotplug可执行程序且没有为其指定,但是至于为什么,现在还没有了解清楚。可能是插入USB wifi后需要处理一系列的热插拔事件,每个处理完了才能进入下一步。

iwconfig配置AP模式master时出错

用iwconfig配置模式的时候会出现配置错误,因为有了前面出错的经验,就直接在源码中寻找问题的所在。最终在函数cfg80211_wext_siwmode中找到问题所在,从代码中可以看出,当遇到配置为master时就会返回错误,然后就会提示配置错误。

int cfg80211_wext_siwmode(struct net_device *dev,
                          struct iw_request_info *info,
			  u32 *mode,
                          char *extra)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_registered_device *rdev;
	struct vif_params vifparams;
	enum nl80211_iftype type;
	int ret;

	rdev = wiphy_to_dev(wdev->wiphy);

	switch (*mode) {
	case IW_MODE_INFRA:
		type = NL80211_IFTYPE_STATION;
		break;
	case IW_MODE_ADHOC:
		type = NL80211_IFTYPE_ADHOC;
		break;
	case IW_MODE_REPEAT:
		type = NL80211_IFTYPE_WDS;
		break;
	case IW_MODE_MONITOR:
		type = NL80211_IFTYPE_MONITOR;
		break;
	default:
		return -EINVAL;
	}

	if (type == wdev->iftype)
		return 0;

	memset(&vifparams, 0, sizeof(vifparams));

	cfg80211_lock_rdev(rdev);
	ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams);
	cfg80211_unlock_rdev(rdev);

	return ret;
}

所以iwconfig不能配置,搜索后发现需使用其他工具iw。只找了一下,由于项目中不需要这个功能,且进度比较紧,所以就直接没有测试它是否真的有效。想配置的可以去尝试一下。

附录:

1、firmware下载链接;

2、ATH9k_htc驱动主页

3、无配置线工具(wireless-tool);

4、新的无线配置工具(iw);

 

10 条评论