arm linux 的驱动编译一般都会有些配置或少量代码修改,特别是自己研发的主板,下面是本人在T113环境下亲自成功编译wifi及ap驱动的日志记录,主板全自主研发,非核心板架构,可能因环境不同步骤略有差异,请自甄别,仅供参考。
WIFI芯片:BL-R8188
RTL18188ETV/RTL8188EUS
1. 编译WIFI驱动
1.下载驱动
https://github.com/lwfinger/rtl8188eu
rtl8188eu-5.2.2.4.zip
rtl8188eus-5.2.2.4.zip
2. 将驱动源码拷贝到内核源码目录
drivers/net/wireless/rtl8188eu
linux-5.4/
├── drivers/
│ ├── net/
│ │ ├── wireless/
│ │ │ ├── rtl8188eu/
│ │ │ │ ├── Makefile
│ │ │ │ ├── Kconfig
│ │ │ │ ├── ... (其他源码文件)
3. 修改drivers/net/wireless/Kconfig
在内核的drivers/net/wireless/Kconfig文件中,添加对rtl8188eu驱动的引用。找到类似以下内容的位置:
source "drivers/net/wireless/realtek/Kconfig"
在其后添加:
source "drivers/net/wireless/rtl8188eu/Kconfig"
4. 修改drivers/net/wireless/Makefile
在内核的drivers/net/wireless/Makefile文件中,添加对rtl8188eu驱动的编译支持。找到类似以下内容的位置:
obj-$(CONFIG_RTL_CARDS) += realtek/
在其后添加:
obj-$(CONFIG_RTL8188EU) += rtl8188eu/
5. 检查rtl8188eu目录下的Kconfig文件
确保rtl8188eu目录下的Kconfig文件内容正确。通常内容如下:
kconfig
config RTL8188EU
tristate "Realtek 8188EU Wireless LAN NIC driver"
depends on USB && CFG80211
select WIRELESS_EXT
select WEXT_PRIV
help
This option enables the Realtek 8188EU USB WiFi driver.
tristate:表示该驱动可以编译为模块(M)或内置到内核(Y)。
depends on:指定依赖项(如USB和CFG80211)。
help:提供驱动的描述信息。
6. 检查rtl8188eu目录下的Makefile
确保rtl8188eu目录下的Makefile文件内容正确。通常内容如下:
obj-$(CONFIG_RTL8188EU) += rtl8188eu.o
rtl8188eu-y := core.o usb.o ...
obj-$(CONFIG_RTL8188EU):根据配置选项CONFIG_RTL8188EU决定是否编译该驱动。
rtl8188eu-y:列出需要编译的源文件。
7. 更新内核配置
在内核源码根目录下,运行以下命令更新配置:
make menuconfig
在配置菜单中,导航到以下路径:
Device Drivers --->
Network device support --->
Wireless LAN --->
[*] Realtek 8188EU Wireless LAN NIC driver
如果一切配置正确,你应该能看到Realtek 8188EU Wireless LAN NIC driver选项。
#有看到:
8. 编译驱动
根据需求选择驱动编译方式:
编译为模块:在menuconfig中选择M,然后编译模块:
make modules
生成的模块文件为rtl8188eu.ko,位于drivers/net/wireless/rtl8188eu/目录下。
编译到内核:在menuconfig中选择Y,然后重新编译内核:
make
#t11i 环境下编译:修改配置后直接buil.sh ,
#如果重新编译,需要删除out/kernel/drivers/net/wireless/rtl8188eu目录下面所有文件,重新编译要改一下.config 文件或者wireless下面的kconfig文件
9. 安装驱动
如果编译为模块,将生成的rtl8188eu.ko文件拷贝到目标系统的模块目录中:
cp drivers/net/wireless/rtl8188eu/rtl8188eu.ko /lib/modules/$(uname -r)/kernel/drivers/net/wireless/
#注意rtl8188eu 需要复制bin文件,驱动源码目录下有 /lib/firmware/rtlwifi/rtl8188eufw.bin
depmod -a
modprobe rtl8188eu
10. 验证驱动
检查驱动是否加载:
lsmod | grep rtl8188eu
如果驱动加载成功,可以使用iwconfig或ip命令检查无线网卡是否正常工作。
#modprobe rtl8188eu.ko,出现错误:Invalid argument
#查看日志:dmesg | tail -n 20
[ 25.581331] Bridge firewalling registered
[ 26.073620] Initializing XFRM netlink socket
[ 33.129374] usb0-vbus: disabling
[ 76.999995] 8188eu: module uses symbol (kernel_read) from namespace VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver, but does not import it.
[ 77.015187] 8188eu: Unknown symbol kernel_read (err -22)
[ 77.077737] 8188eu: module uses symbol (kernel_read) from namespace VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver, but does not import it.
[ 77.092947] 8188eu: Unknown symbol kernel_read (err -22)
#问题分析:
错误提示表明模块尝试调用属于 VFS 内部命名空间 (VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver) 的符号 kernel_read,但未在模块中显式声明依赖该命名空间28。
内核版本限制:Linux 5.4+ 对 VFS 层符号的导出策略更严格,部分文件系统相关函数被限制在特定命名空间内,模块默认无法直接调用28。
符号导出策略变更:kernel_read 在高版本内核中归类为文件系统内部接口,非通用驱动 API8。
2. 适配方案
方案一:显式声明命名空间依赖
在模块源码中添加命名空间导入声明:
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
操作步骤:
在模块源码文件末尾(module_exit 后)添加上述声明。
确保内核配置启用 CONFIG_MODULE_IMPORT_NS(默认开启)28。
11. 修改驱动源码
源码目录下usb_intf.c
module_init(rtw_drv_entry);
module_exit(rtw_drv_halt);
#增加下面这行 ,
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
#重新编译 modprobe 8188eu 加载驱动成功
12. 只有wlan0,无线网卡能正常通信,但是没有AP 功能
总结
通过以上步骤,你可以将rtl8188eu驱动集成到ARM Linux 5.4内核中,并在内核配置菜单中可见和可选。如果遇到问题,可以检查Kconfig和Makefile的配置是否正确,以及驱动源码是否完整。
#以下错误这是使用rtl8188eus-5.2.2.4.zip才有此错误,使用https://github.com/lwfinger/rtl8188eu 不会
#错误1 解决
EXTRA_CFLAGS += -I$(src)/include 也有,但是还是 找不到文件:drv_types.h: No such file or directory
方法 1:使用绝对路径
将EXTRA_CFLAGS中的路径改为绝对路径。例如:
//我重新定义src的绝对路径
src = /home/uw/t113i/T113-i_v1.0/kernel/linux-5.4/drivers/net/wireless/rtl8188eu
EXTRA_CFLAGS += -I$(src)/include
#错误2 在编译 rtl8188eu 驱动时,出现以下错误:
/drivers/net/wireless/rtl8188eu/os_dep/linux/os_intfs.c:1240:22: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.ndo_select_queue = rtw_select_queue,
这个错误的原因是 ndo_select_queue 的函数签名与 rtw_select_queue 的函数签名不匹配。具体来说,ndo_select_queue 是 Linux 内核网络设备操作结构体 net_device_ops 中的一个成员,它的函数签名在内核版本之间可能发生了变化。
1. 问题分析
在较新的 Linux 内核版本中,ndo_select_queue 的函数签名可能已经更新,而 rtl8188eu 驱动中的 rtw_select_queue 函数可能仍然使用旧的签名,导致类型不匹配。
ndo_select_queue 的函数签名
在较新的内核版本中,ndo_select_queue 的函数签名通常如下:
u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev);
rtw_select_queue 的函数签名
在 rtl8188eu 驱动中,rtw_select_queue 的函数签名可能是:
u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb);
由于函数签名不匹配,编译器会报错。
2. 解决方法
根据内核版本的不同,有以下几种解决方法:
方法 1:修改 rtw_select_queue 的函数签名
将 rtw_select_queue 的函数签名修改为与 ndo_select_queue 一致。例如:
u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev)
{
// 忽略 sb_dev 参数(如果需要)
return rtw_select_queue_original(dev, skb);
}
然后更新 net_device_ops 结构体中的初始化:
.ndo_select_queue = rtw_select_queue,
方法 2:使用条件编译适配不同内核版本
在内核驱动中,通常使用条件编译来适配不同版本的内核。可以通过检查内核版本来选择正确的函数签名。例如:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev)
{
// 新内核版本的实现
return rtw_select_queue_original(dev, skb);
}
#else
u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb)
{
// 旧内核版本的实现
return rtw_select_queue_original(dev, skb);
}
#endif
方法 3:忽略 sb_dev 参数
如果 sb_dev 参数在驱动中不需要使用,可以直接忽略它。例如:
u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev)
{
// 忽略 sb_dev 参数
return rtw_select_queue_original(dev, skb);
}
3. 修改 os_intfs.c 文件
在 os_intfs.c 文件中,找到 rtw_select_queue 函数的定义,并根据上述方法修改其签名。然后更新 net_device_ops 结构体中的初始化。
例如:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev)
{
// 新内核版本的实现
return rtw_select_queue_original(dev, skb);
}
#else
u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb)
{
// 旧内核版本的实现
return rtw_select_queue_original(dev, skb);
}
#endif
static const struct net_device_ops rtw_netdev_ops = {
.ndo_select_queue = rtw_select_queue,
// 其他成员
};
4. 重新编译驱动
修改完成后,重新编译驱动:
#我的解决方案 ,操其他驱动对应地方修改
static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
, struct net_device *sb_dev
#else
, void *accel_priv
#endif
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)))
, select_queue_fallback_t fallback
#endif
#endif
)
/*
#if (LINUX_VERSION_CODE>=KERNEL_VERSION(4,19,0))
static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev,
select_queue_fallback_t fallback)
#else
static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
, void *accel_priv
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
, select_queue_fallback_t fallback
#endif
#endif
)
#endif
*/
2. 实现STA+AP双模式
#注意,网上多数文章实现双模式都是有这样那样的问题,下面方法是我自己分析修改代码后成功实现STA+AP双模式:(基于前面成功但只有wlan0的改过的源码驱动)
1. 源码:https://github.com/lwfinger/rtl8188eu
rtl8188eu-5.2.2.4.zip
2. 修改内核Makefile,下面我修改的实际文件 ,其他地方不用修改
EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS)
EXTRA_CFLAGS += -O1 -g
EXTRA_CFLAGS += -Wno-unused-variable
EXTRA_CFLAGS += -Wno-unused-value
EXTRA_CFLAGS += -Wno-unused-label
EXTRA_CFLAGS += -Wno-unused-parameter
EXTRA_CFLAGS += -Wno-unused-function
EXTRA_CFLAGS += -Wno-unused
EXTRA_CFLAGS += -Wno-uninitialized
EXTRA_CFLAGS += -Wno-missing-prototypes
EXTRA_CFLAGS += -Wno-missing-declarations
#gaobaowei add
#EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DLINUX_KERNEL_5_4
GCC_VER_49 := $(shell echo `$(CC) -dumpversion | cut -f1-2 -d.` \>= 4.9 | bc )
ifeq ($(GCC_VER_49),1)
EXTRA_CFLAGS += -Wno-date-time # Fix compile error && warning on gcc 4.9 and later
endif
EXTRA_CFLAGS += -I$(src)
CONFIG_AUTOCFG_CP = n
#gaobaowei add
# 强制启用AP+STA双模(替代CONFIG_AP_MODE/CONFIG_CONCURRENT_MODE)
EXTRA_CFLAGS += -DCONFIG_AP_MODE -DCONFIG_CONCURRENT_MODE
EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
CONFIG_CONCURRENT_MODE = y
CONFIG_IOCTL_CFG80211 = y
CONFIG_BT_COEXIST = n
########################## Features ###########################
CONFIG_MP_INCLUDED = y
#CONFIG_POWER_SAVING = y
#gaoboawei add
CONFIG_POWER_SAVING = n
CONFIG_EFUSE_CONFIG_FILE = y
CONFIG_TRAFFIC_PROTECT = y
CONFIG_LOAD_PHY_PARA_FROM_FILE = y
CONFIG_RTW_ADAPTIVITY_EN = disable
CONFIG_RTW_ADAPTIVITY_MODE = normal
CONFIG_BR_EXT = y
CONFIG_RTW_NAPI = y
CONFIG_RTW_GRO = y
########################## Debug ###########################
CONFIG_RTW_DEBUG = y
# please refer to "How_to_set_driver_debug_log_level.doc" to set the available level.
CONFIG_RTW_LOG_LEVEL = 2
######################## Wake On Lan ##########################
CONFIG_WAKEUP_GPIO_IDX = default
######### Notify SDIO Host Keep Power During Syspend ##########
CONFIG_RTW_SDIO_PM_KEEP_POWER = y
###################### Platform Related #######################
CONFIG_PLATFORM_I386_PC = n
###############################################################
3. Kconfig
内核目录:Kconfig
config RTL8188EU
tristate "Realtek 8188EU USB WiFi"
depends on WLAN && USB
---help---
Help message of RTL8188EU
上级目录:Wireless\Kconfig
添加:
source "drivers/net/wireless/bcmdhd/Kconfig"
source "drivers/net/wireless/aic8800/Kconfig"
#添加下面
source "drivers/net/wireless/rtl8188eu/Kconfig"
4. 修改内核配置:
和前面一样:
5. build.sh
build.sh pack
烧系统
modprobe 8188EU
ifconfig -a 可以看到wlan0 wlan1(注意,这里我没有拷贝bin文件,就可以了)
6319

被折叠的 条评论
为什么被折叠?



