最近打算把闲置了许久的树莓派重新利用起来。交给它的第一个任务是:做路由器。于是去弄了个 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
变量就可以交叉编译成功。