一、SDIO 设备驱动移植
(1)修改SD卡驱动使内核支持SD卡
修改文件:arch/arm/mach-s3c2410/mach-smdk2410.c
添加所需头文件:
#include<mach/gpio.h>
#include<linux/mmc/host.h>
#include<plat/mci.h>
//增加平台设备对sd卡的支持
static struct platform_device *smdk2410_devices[] __initdata = {
&s3c_device_ohci,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_sdi,
};
添加平台数据dev->platform_data
Static struct s3c24xx_mci_pdata smdk2410_mmc_cfg__initdata={
.gpio_detect = S3C2410_GPG(10),
.set_power = NULL,
.ocr_avail = MMC_VDD_32_33,
};
(2)在smdk2410_init中添加
S3c24xx_mci_set_platdata(&smdk2410_mmc_cfg);
二、配置内核以支持Marvel无线WIFI
选择35内核中的wlan marwell sdio模块
device drivers ----> |
三、编译内核,生成驱动模块
(1)先执行make 然后make modules //内核生成模块的方式
(2)将生成的wlan相关ko文件拷贝到目标板中,在这我放在/sdio目录下
home/kernel/linux-2.6.35/drivers/net/wireless/libertas/$ cp libertas.ko libertas_sdio.ko /rootfs/filesystem/sdio/
/rootfs/filesystem/sdio$ls
libertas.ko libertas_sdio.ko
(3)把固件helper_sd.bin sd8686.bin拷贝到相应的位置/rootfs/filesystem/lib/firmware/mrvl/ (Android中wifi.c有定义,属于HAL层,后面两个目录是自己创建的)
(4)在目标板子插入SDIO WIFI 并加载驱动
首先插入SDIO WIFI 然后加载驱动
/sdio#insmod libertas.ko
/sdio#insmod libertas_sdio.ko helper_name=/lib/firmware/mrvl/helper_sd.bin fw_name=/lib/firmware/mrvl/sd8686.bin (注意要在一行)
驱动加载完成会提示:(注意:如果没有,则再次热插拔你的sdio wifi卡便可以看到)
if_sdio_intterupt
libertas: 00:01:36:19:b3:6b, fw 9.70.3p23, cap 0x00000303
if_sdio_intterupt
libertas: wlan0: Marvell WLAN 802.11 adapter
sdio_havefister_driver
sdio_init_module have done
四、制作无线测试工具
测试无线网卡用无线工具iwconfig iwlist等命令是通过开源软件wireless_tools_29.rar编译得到。
步骤:
(1)首先在windows目录解压上面那个软件包,把解压后的文件夹复制到虚拟机/home$ls
wireless_tools_29
/home/wireless_tools_29$
(2)修改Makefile
8 PREFIX = /home/wtools //指定安装路径 12 CC = arm-linux-gnu-gcc (和编译你的文件系统所用保持一致,也可静态编译,对Makefile适当修改) 14 AR = arm-linux-gnu-ar |
1. 前言
硬件平台: imx27+sd8686 软件平台: linux 内核: 2.6.27 2. 移植思想 1, WIFI 模块本身和 cpu 之间的接口; 我们的模块和 cpu 之间的接口是 sdio 的,也就是说必须要先保证 SDIO 本身是工作的,与SD卡,MMC属于同类型。 主要用到这几个GPIO引脚SD0...SD3,SD2_CMD,SD2_CLK,以及复位引脚PB24. 2, WIFI 模块本身的上电时序; 模块都有它自己的规律,所以必须要根据 spec 了解它本身的上电过程,严格遵守; 3, 以太网接口的创建; 我们的 WIFI 模块本身是建立在 SDIO 口之上的,而对上都是提供以太网接口的,所以必须要保证这个接口以及创建; 4, 特殊处理; 不同的模块都有它特别的地方,比如我们用的是 8686 和 compo 也就是说它和蓝牙共用天线,所以需要在初始化的时候做特殊的处理,发送特殊的命令,才能工作; 3. 移植过程 1, sdio 本身是通过 gpio 口模拟的,所以需要对 gpio 口进行配置 ; static mfp_cfg_t littleton_mmc3_pins[] = { GPIO7_2_MMC3_DAT0, GPIO8_2_MMC3_DAT1, GPIO9_2_MMC3_DAT2, GPIO10_2_MMC3_DAT3, GPIO103_MMC3_CLK, GPIO105_MMC3_CMD, }; 2, wifi 模块本身的初始化 ; #define MFP_WIFI_V18_ENABLE (GPIO26_GPIO) #define MFP_WLAN_RESETN (GPIO99_GPIO) #define WIFI_WAKEUP_HOST (GPIO104_GPIO) /*error must be changed*/ #define WLAN_ENABLE_PIN 26 #define WLAN_RESET_PIN 99 #define M200_B #ifdef M200_B #define BT_RESET_PIN EXT1_GPIO(1) #define BT_RESET_GPIO (GPIO1_2_GPIO) #else #define BT_RESET_GPIO (GPIO6_2_GPIO) #define BT_RESET_PIN EXT1_GPIO(6) #endif static mfp_cfg_t lin2008_wifibt_pins[] = { MFP_WIFI_V18_ENABLE, MFP_WLAN_RESETN, WIFI_WAKEUP_HOST,/*wakeup host*/ }; static mfp_cfg_t lin2008_wifibt_pins2[] = { MFP_WIFI_V18_ENABLE, }; static int wifibt_power_status; int lin2008_poweron_wifibt_board(void) { if (!wifibt_power_status) { mxc_mfp_config(ARRAY_AND_SIZE(lin2008_wifibt_pins));
gpio_direction_output(WLAN_ENABLE_PIN, 1); gpio_direction_output(WLAN_RESET_PIN, 1); gpio_direction_output(BT_RESET_PIN,1); mdelay(10); gpio_direction_output(BT_RESET_PIN, 0); gpio_direction_output(WLAN_RESET_PIN, 0); // bt need > 5 ms to reset mdelay(5); gpio_direction_output(BT_RESET_PIN, 1); gpio_direction_output(WLAN_RESET_PIN, 1); wifibt_power_status++; return 0; } wifibt_power_status++; return 1; } int lin2008_poweroff_wifibt_board(void) { wifibt_power_status--; if (!wifibt_power_status) { mxc_mfp_config(ARRAY_AND_SIZE(lin2008_wifibt_pins2)); gpio_direction_output(WLAN_ENABLE_PIN, 0); return 0; } return 1; } 3, 以太网接口的创建 这里在 android 平台上要做特殊的处理,也就是 firmware 的位置要放好,否则加载 firmware 始终不成功,那么以太网接口就不会被创建了; 需要把 helper_sd.bin 放在 /lib/firmware/mrvl 下面(若没有,则创建一个); 把 sd8686.bin 放在 /lib/firmware/mrvl 下面(同上); 4, 特殊的处理 对于 8686 模块需要做特殊的处理,在注册完以太网接口以后,需要添加下面这段话 : { #define BCA_CFG_NUM_OF_MODES 4 #define BCA_CFG_SINGLE_ANT_WITH_COEX 0 #define BCA_CFG_DUAL_ANT_WITH_COEX 1 #define BCA_CFG_SINGLE_ANT_FOR_BT_ONLY 2 #define BCA_CFG_MRVL_DEFAULT 3 #define BCA_CONFIG BCA_CFG_SINGLE_ANT_WITH_COEX static u32 BCACfgTbl[BCA_CFG_NUM_OF_MODES][3] = { //0xA5F0, 0xA58C, 0xA5A0 { 0xa027181c, 0x40214, 0xd24d}, //Mode 0: Single ANT with COEX enable { 0xa027181c, 0x40211, 0xd24d}, //Mode 1: Dual ANT with COEX enable { 0xa027181c, 0x40222, 0xd21c}, //Mode 2: single ANT for BT only { 0xa027801d, 0x18000, 0xd21c}, //Mode 3: Marvell default };
wlan_offset_value RegBuffer;
RegBuffer.offset = (0xA5F0); RegBuffer.value = BCACfgTbl[BCA_CONFIG][0]; wlan_prepare_cmd(priv, HostCmd_CMD_MAC_REG_ACCESS, HostCmd_ACT_GEN_SET, HostCmd_OPTION_WAITFORRSP, 0,&RegBuffer); RegBuffer.offset =(0xA58C); RegBuffer.value = BCACfgTbl[BCA_CONFIG][1]; wlan_prepare_cmd(priv, HostCmd_CMD_MAC_REG_ACCESS, HostCmd_ACT_GEN_SET, HostCmd_OPTION_WAITFORRSP, 0,&RegBuffer); RegBuffer.offset = (0xA5A0); RegBuffer.value = BCACfgTbl[BCA_CONFIG][2]; wlan_prepare_cmd(priv, HostCmd_CMD_MAC_REG_ACCESS, HostCmd_ACT_GEN_SET, HostCmd_OPTION_WAITFORRSP, 0,&RegBuffer); } 基本上这样就可以工作了; 4. 其它问题 Sdio 口默认是用的 3.2V 这里需要修改相关的地方强制设成是 1.8V ,否则 SDIO 接口将无法工作; Linux平台上需要移植一些上层软件才能验证,比如 iwconfig , iwlist 等。 测试步骤: ifconfig eth0 up iwlist eth0 scanning 如果能扫描到 AP 那么证明基本已经 OK 了; iwconfig eth0 iwlist eth0 freq 可以查看设备的相关信息,查看各项是否正常。 现在,就可以 ping 通 IP 地址了; 5. 常见问题 1, WIFI 驱动注册 sdio 驱动的时候出错,也就是 probe 函数未被调用? 需要检查 sdio 设备本身是否被检测到,内核是通过发送特定的命令来检测是 sdio 是 SD 卡还是 mmc 的, 在 mmc_rescan 函数里面可以看到 sdio 设备的加载过程,有可能就是你的电压设置不对; 2, 以太网接口一直出不来或者说 firmware 加载失败? 这里需要确保 firmware 是否正确被加载,很可能是它找不到对应的 firmware ,可以通过添加打印信息看看,它的路径到底是在什么地方,对于 wifi 来说 helper_sd.bin 需要放在 /lib/firmware/ 下面,而 sd8686.bin 需要放在 /lib/firmware/mrvl 下面; 3, 一切正常,但是调用 iwlist eth0 scanning 的时候,扫描不到任何结果,出现NO scan results? 这时候需要做特殊的处理,比如共存代码的设置,是否正常等,通常可以判断有没有中断上来,以此区分到底是模块和cpu 的连接问题还是模块本身的设置问题; 4, 工作一段时间后不正常 这个有可能是蓝牙模块需要进行初始化,因为它们是共用天线,有时候不起蓝牙模块对应的 40M 时钟就不起来; 本人参照:http://blog.chinaunix.net/u2/67984/showart_2113942.html 此博客而移植成功的。 在此感谢wylhistory! |
目前sourceforge网站上提供了Linux 2.6.18版本内核的sdiostack补丁,使用此补丁后可以编译出供Atheros SDIO wifi v1.0模块使用的驱动。
首先选择工作目录(例如当前用户的个人目录/home/~),此后的操作都在此目录下进行。下面以Samsung S3C2410平台为例介绍驱动编译过程,使用的交叉编译工具为arm-linux-gcc v3.4.6。
1. 下载内核压缩包并解压。
tar zxvf linux-2.6.18.tar.gz
2. 下载sdiostack驱动并解压至内核源码目录,补丁包含5个patch文件和1个series文件,按照series文件中的顺序依次打补丁。
tar zxvf sdio-linux-2.6.18.tar.gz -C linux-2.6.18/
cd linux-2.6.18/
patch -p1 < common_atheros_sdiostack.patch
patch -p1 < common_atheros_sdiostack_shcd.patch
patch -p1 < common_atheros_sdiostack_functions.patch
patch -p1 < common_atheros_sdiostack_sample_fd.patch
patch -p1 < common_atheros_sdiostack_benchmark.patch
patch -p1 < common_atheros_sdiostack_ar6000_wlan.patch
3. 可以从配置路径拷贝s3c2410配置模板后再对其修改。
cp arch/arm/configs/s3c2410_defconfig .config
需要开启Device Drivers-->Plug and Play support-->Plug and Play support选项支持PnP。
需要开启Device Drivers-->Network device support-->Wireless LAN (non-hamradio)--> Wireless LAN drivers (non-hamradio) & Wireless Extensions选项,否则无法找到wireless_send_event函数定义。
make menuconfig
4. drivers/pnp/resource.c中的request_dma和free_dma函数需要删除,不然在稍后的编译中会造成缺少定义的错误(我始终未能让resource.c成功的找到这两个相关的dma函数实现,最后只能注释掉了,如果有了解的朋友,希望能告诉我正确的做法)。然后开始内核编译操作。
make
5. 最后在drivers/sdio/对应目录下生成驱动各个模块。sdiostack补丁中只提供了很少几种平台的hcd模块代码,如果缺少对应目标平台的代码,还需要自己移植。以下4个模块为必须的最小配置。
lib/sdio_lib.ko
busdriver/sdio_busdriver.ko
function/wlan/ar6000/ar6000.ko
hcd/s3c2412/sdio_s3c2410_hcd.ko
注意:编译sdiostack驱动时使用的内核版本需要和目标平台上的内核版本一致,如果不是2.6.18版本的内核,在打补丁过程中可能会有提示信息,可以根据提示信息手工修改。不同平台的内核配置选项也会有所不同,可能需要对配置做少许调整。一般来说,补丁中包含的hcd模块代码不能满足需要,所以要想最终能使用SDIO WIFI网卡,最困难的地方在于如何获取缺少的这一部分的代码。MontaVista也提供了一个补丁下载,我没有用过这个补丁,但是其中包含的sdiostack文档是很好的资料。如果希望使用Atheros SDIO wifi v2.0,可以看看openmoko补丁。下一步,我将尝试编译wifi v2.0的驱动。