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 条评论