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

2012-03-02 由 创建在标签 开发

最近忙一个项目的无线模块,使用的是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 条评论

  • hejun 说道:

    你好,我是在mips嵌入式板子上移植这个,内核版本是2.6.29 碰到找不到htc_9271.fw的错误,其实已经放到/lib/firmware下面,可否详细指点下,或者看下你的hotplug脚本是怎样写的,谢谢!!!

    • gaoliang 说道:

      我上面有说,也已经把我自己的热插拔脚本放在上面了,但是你还需要确认一下你们有没有使用mdev。你可以把你的热插拔脚本发过来给我看一下。

  • oy 说道:

    有时间交流,我也移植wifi 9271
    firmware没有加载时因为busybox没有配置firmware,mdev没有加载firmware。

  • oy 说道:

    麻烦问一下,你是如何解决compat-2.6.29.h:155: error: redefinition of ‘struct net_device_ops’ 这种问题,我是直接屏蔽掉。但是在运行时候,会在netif_napi_add 地方会死机,不知道你是如何解决的。

    • gaoliang 说道:

      这个你查看一下头文件包含关系,确定一下重复定义即可。你最好能够把调试信息定位一下,看下为什么会走到那里,那样会更容易定位

  • oy 说道:

    这个你可以看一下,busybox的.config 配置文件,然后在mdev.c 可以查到,调用/lib/firmware ,因为compat-firmware 会发出一个firmware的uevent,然后这个uevent会被busybox的mdev捕获到,调用加载/lib/firmware内的相关信息。我也是跟代码查到的。

    • gaoliang 说道:

      是这样的,但是这个加载firmware需要内核支持。你这个地方可能内核不能正常处理,因为你的firmware在用户空间,需要内核配置一下。

  • oy 说道:

    麻烦问一下,你碰到如下的死机没有呀。
    [FUNCTION:ieee80211_register_hw LINE959] &local->napi_dev 8f8e4a98, &local->napi 8f8e4e18, local->hw.napi_weight 0CPU 0 Unable to handle kernel paging request at virtual address 00000004, epc == 80382228, ra == c10cbbc0
    Oops[#1]:
    Cpu 0
    $ 0 : 00000000 00000000 8f8e4e2c 00000000
    $ 4 : 8f8e4a98 8f8e4e18 c10cb1b4 00000040
    $ 8 : 8f1a9fe0 00008c00 00000000 8f8ce000
    $12 : 80756e18 80756e18 8ef10a88 806e94f0
    $16 : 00000000 8f8e4e18 8f8e42c0 8f8e4a98
    $20 : 8dd1c01c 8f8e42c0 8f8e4e40 00000000
    $24 : 00000008 8035cdcc
    $28 : 8f1a8000 8f1a9bc8 8ed1a801 c10cbbc0
    Hi : 000f41fb
    Lo : cd435ac0
    epc : 80382228 netif_napi_add+0×20/0×58
    Not tainted
    ra : c10cbbc0 ieee80211_register_hw+0×650/0×744 [mac80211]
    Status: 11008c03 KERNEL EXL IE
    Cause : 4080800c
    BadVA : 00000004
    PrId : 00019655 (MIPS 24Kc)
    Modules linked in: ath9k_htc(+) ath9k_common ath9k_hw ath mac80211 cfg80211 compat_firmware_class rfkill_backport compat rfkill
    Process insmod (pid: 548, threadinfo=8f1a8000, task=8f8f4500, tls=00539490)
    Stack : 8dd1c000 c10f9e80 000003bf 8f8e4a98 8f8e4e18 00000000 fffffffe 8f8e42c0
    8dd1c000 8dd1c0c4 8f8e42c0 8dd1c000 802a4f6c c17c66d4 0000003f c17c75a8
    8ed1b0ac 00000001 00000003 00000004 000007d0 80182384 00000008 03000100
    00000000 8f8e4e40 c17bff14 c17bed5c 0dd99000 8f803300 8f801300 80790000
    00000000 8f801300 000000d0 00000001 000000d0 8f811e60 00000039 00000040

    Call Trace:
    [] netif_napi_add+0×20/0×58
    [] ieee80211_register_hw+0×650/0×744 [mac80211]
    [] ath9k_htc_probe_device+0xbb4/0xdd8 [ath9k_htc]
    [] ath9k_htc_hw_init+0×20/0×50 [ath9k_htc]
    [] ath9k_hif_usb_probe+0×984/0xa6c [ath9k_htc]
    [] usb_probe_interface+0×104/0×150
    [] driver_probe_device+0xf8/0x1f4
    [] __driver_attach+0x6c/0xa4
    [] bus_for_each_dev+0×58/0x9c
    [] bus_add_driver+0xc4/0×248
    [] driver_register+0xb4/0×164
    [] usb_register_driver+0×84/0×110
    [] ath9k_htc_init+0×18/0×48 [ath9k_htc]
    [] do_one_initcall+0×64/0x1c4
    [] sys_init_module+0xa4/0x1ac
    [] stack_done+0×20/0x3c

    • gaoliang 说道:

      这个东西我还是去年做的,有了很长时间了,开始也是firmware加载失败导致内核错误。
      我看你的错误应该是硬件初始化的时申请地址出错了,不知道是不是firmware导致的。你查看一下你的内核配置,看看下面几个选项你配置了没有。
      Device Drivers —>
      Generic Driver Options —>
      Userspace firmware loading support
      [*] Include in-kernel firmware blobs in kernel binary
      我的内核是2.6.18,你参考看看内核是不是配置了。

发表评论