最近打算把闲置了许久的树莓派重新利用起来。交给它的第一个任务是:做路由器。于是去弄了个 USB 无线网卡,型号是 TP-Link WN823N 版本 2.0。买的时候没注意,拿到手才知道这款需要自行安装驱动。还得使用特制版本的 hostapd。
驱动名叫 8192eu,或者 rtl8192eu,随便啦。GitHub 上有多个版本,我使用的是 Mange/rtl8192eu-linux-driver。因为 gcc 及内核更新的原因,需要修改两处:
diff --git a/Makefile b/Makefile
index 0c800f8..85058fa 100644
--- a/Makefile
+++ b/Makefile
@@ -13,6 +13,7 @@ EXTRA_CFLAGS += -Wno-unused-label
EXTRA_CFLAGS += -Wno-unused-parameter
EXTRA_CFLAGS += -Wno-unused-function
EXTRA_CFLAGS += -Wno-unused
+EXTRA_CFLAGS += -Wno-date-time
#EXTRA_CFLAGS += -Wno-uninitialized
diff --git a/os_dep/linux/rtw_android.c b/os_dep/linux/rtw_android.c
index 98f0d31..8a2ee56 100644
--- a/os_dep/linux/rtw_android.c
+++ b/os_dep/linux/rtw_android.c
@@ -337,7 +337,7 @@ int rtw_android_cmdstr_to_num(char *cmdstr)
{
int cmd_num;
for(cmd_num=0 ; cmd_num<ANDROID_WIFI_CMD_MAX; cmd_num++)
- if(0 == strnicmp(cmdstr , android_wifi_cmd_str[cmd_num], strlen(android_wifi_cmd_str[cmd_num])) )
+ if(0 == strncasecmp(cmdstr , android_wifi_cmd_str[cmd_num], strlen(android_wifi_cmd_str[cmd_num])) )
break;
return cmd_num;
然后,本文的主题来了:我需要 ARM 版的驱动!因为我的树莓派没有键盘也没有显示器,也没有网线什么的。除了电源和 SD 卡,它只有一块无线网卡了。所以只能交叉编译了。
本来呢,内核使用的构建系统非常棒,一切都会很顺利的。但是,我不要先交叉编译个 ARM 版内核。于是我遇到了这个问题。scripts
目录下的二进制文件是编译模块的时候需要执行的,然而我的机器并不能执行 ARM 版本的二进制。
好吧,不就是一些小程序么。把我本机的复制过去就可以跑了嘛。结果开心地看着各源码文件被编译成目标文件之后,遇到 modpost 报了这么个错误:
FATAL: section header offset=11258999068426292 in file '/ldata/DATA/src/rtl8192eu-linux-driver/8192eu.o' is bigger than filesize=1094666
大概是因为我的系统是 64 位的,然而 ARM 是 32 位的吧。不过我没兴趣去找一个 i686 版本的 modpost 来尝试了。真要在我笔记本上跑 ARM 程序又不是不可以,我们有 qemu 嘛。虽然是模拟器,不过我不觉得它会比在我那树莓派上运行慢 :-)
以下是整个完整的步骤:
首先说明一点,我使用的是 Arch Linux ARM。树莓派官方提供的 Raspberry 镜像里东西太多了,我的 SD 卡放不下我也用不着。而且它是基于 Debian Wheezy 的,没有 systemd 可用。
新建一个目录rpi
,开始啦!
因为要运行 ARM 版的 modpost 程序,我们先下载树莓派的 gcc-libs、glibc,并解压出其 /usr/lib 下的文件:
wget https://mirrors.ustc.edu.cn/archlinuxarm/armv6h/core/gcc-libs-5.2.0-2-armv6h.pkg.tar.xz https://mirrors.ustc.edu.cn/archlinuxarm/armv6h/core/gcc-libs-5.2.0-2-armv6h.pkg.tar.xz.sig https://mirrors.ustc.edu.cn/archlinuxarm/armv6h/core/glibc-2.22-1-armv6h.pkg.tar.xz https://mirrors.ustc.edu.cn/archlinuxarm/armv6h/core/glibc-2.22-1-armv6h.pkg.tar.xz.sig
gpg --verify glibc-2.22-1-armv6h.pkg.tar.xz.sig
tar xf glibc-2.22-1-armv6h.pkg.tar.xz usr/lib || true
gpg --verify gcc-libs-5.2.0-2-armv6h.pkg.tar.xz.sig
tar xf gcc-libs-5.2.0-2-armv6h.pkg.tar.xz usr/lib
[[ ! -f lib ]] && ln -s usr/lib lib
要编译内核模块,当然少不了 linux-*-headers 包了:
wget https://mirrors.ustc.edu.cn/archlinuxarm/armv6h/core/linux-raspberrypi-headers-4.1.6-3-armv6h.pkg.tar.xz https://mirrors.ustc.edu.cn/archlinuxarm/armv6h/core/linux-raspberrypi-headers-4.1.6-3-armv6h.pkg.tar.xz.sig
gpg --verify linux-raspberrypi-headers-4.1.6-3-armv6h.pkg.tar.xz.sig
tar xf linux-raspberrypi-headers-4.1.6-3-armv6h.pkg.tar.xz usr
不必每次更新 gcc-libs 和 glibc,只要它们能跑 modpost 程序就可以了。但是内核头文件是要和系统上运行的内核匹配的。
我们删掉 ARM 版的 scripts 目录,换上本机的版本。但是 modpost 例外。同时要修改 Makefile.modpost,使之使用 qemu-arm 来运行 modpost 程序:
pushd usr/lib/modules/4.1.6-3-ARCH/build
mv scripts/mod/modpost .
rm -rf scripts
cp -r /usr/lib/modules/$(uname -r)/build/scripts .
sed -i '/^modpost =/s/scripts/qemu-arm scripts/' scripts/Makefile.modpost
mv modpost scripts/mod
popd
最后就可以编译啦。把交叉编译工具链(签名)的路径加到 $PATH 里去。还要设置 QEMU_LD_PREFIX 到我们解压出来的那些文件所在的目录好让 qemu-arm 能够找到需要的库文件。然后进入驱动目录,开始编译!
path+=/ldata/DATA/soft/arm-lilydjwg-linux-gnueabi/bin
export QEMU_LD_PREFIX=$PWD
cd ../rtl8192eu-linux-driver
make CROSS_COMPILE=arm-lilydjwg-linux-gnueabi- KSRC=../rpi/usr/lib/modules/4.1.6-3-ARCH/build ARCH=arm
gzip 8192eu.ko
就酱。
试错几次之后,终于把配置写对了,于是我看到树莓派的 Wi-Fi 灯闪动了,随即从系统日志看到 hostapd 和 dnsmasq 都报告它连上网了~然后 ssh 登陆过去:
Last login: Tue Jun 11 22:57:29 2013 from 192.168.2.101
两年零三个月没进去过了呢。然后,我换 USTC 源,执行了pacman -Syu
!跨越两年零三个月的滚动更新,然而除了很多配置文件有新版本需要手工合并外,并没有发生什么特别的事情,就更没有滚挂了=w=
后来我也尝试在树莓派上直接编译内核模块(因为内核升级了嘛)。结果表明,交叉编译是正确的选择!在树莓派上编译这个模块的时间,我的笔记本估计可以编译出整个内核了……
这是我编译的 8192eu 模块 及签名文件,对应内核版本 4.1.6。
至于 hostapd,下载这个,把其中的wpa_supplicant_hostapd-0.8_rtw_r7048.20130424.tar.gz
里hostapd
目录下的东西编译了就好。只需要指定CC
变量就可以交叉编译成功。
这是我编译的 hostapd 及签名文件。配置文件中要写driver=rtl871xdrv
。