Another attempt at rtl8812au but the build does not generate the kernel module

Hi,

I am trying to add a kernel module for a 5GHz WiFi USB dongle based on the Realtek RTL8812 chip.
The dongle came with Linux driver source code which claims to support MIPS Linux kernels up to 4.11.
My OpenWrt build target is 18.06 on a TP-LINK 3020 variant (ar71xxx).

The problem is, when I go to build this firmware the rtl8812au.ko module does not get built even though 'rtl8812au' is selected via make menuconfig and the relevant Makefile is being invoked.

Here are the details ...

I have gone through the usual OpenWrt build preparation and confirms it successfully builds firmware without the 'rtl8812au' being in the directory tree.

I created the directory openwrt/packages/kernel/rtl88a12au and created a Makefile in that directory.
I created the directory openwrt/package/kernel/rtl8812au/src and populated it with the source code supplied with the USB dongle.
End result is this directory structure ...

package/kernel/rtl8812au:
total 8
-rw-rw-r-- 1 jeremy jeremy 3832 Nov 29 11:07 Makefile
drwxrwxr-x 7 jeremy jeremy 4096 Nov 29 11:05 src

package/kernel/rtl8812au/src:
total 280
-rw-rw-r-- 1 jeremy jeremy 64 Nov 28 12:28 clean
drwxrwxr-x 4 jeremy jeremy 4096 Nov 28 12:28 core
drwxrwxr-x 8 jeremy jeremy 4096 Nov 28 12:28 hal
-rw-rw-r-- 1 jeremy jeremy 54 Nov 28 12:28 ifcfg-wlan0
drwxrwxr-x 5 jeremy jeremy 12288 Nov 28 12:28 include
-rw-rw-r-- 1 jeremy jeremy 120 Nov 28 12:28 Kconfig
-rw-rw-r-- 1 jeremy jeremy 63452 Nov 29 11:05 Makefile
drwxrwxr-x 3 jeremy jeremy 4096 Nov 28 12:28 os_dep
drwxrwxr-x 2 jeremy jeremy 4096 Nov 28 12:28 platform
-rw-rw-r-- 1 jeremy jeremy 170075 Nov 28 12:28 ReleaseNotes.pdf
-rw-rw-r-- 1 jeremy jeremy 423 Nov 28 12:28 runwpa
-rw-rw-r-- 1 jeremy jeremy 294 Nov 28 12:28 wlan0dhcp

Here is the Makefile I created in package/kernel/rtl8812au (you'll notice I've added some trace writes in the effort to work out what is going on):

#
# Copyright (C) 2006 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# An attempt to support a 5GHz WiFi USB stick based on Realtek 8811AC chip,
# using the driver source code supplied with the USB stick.
#

include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
include $(INCLUDE_DIR)/kernel-defaults.mk

PKG_NAME:=rtl8812au
PKG_RELEASE:=1

# PKG_SOURCE_PROTO:=git
# PKG_SOURCE_URL:=https://github.com/gnab/rtl8812au.git
# PKG_SOURCE_VERSION:=744ebd966f2d967097b780f8d84b683b403f6db2
# PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_SOURCE_VERSION)
# PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_VERSION).tar.gz

# PKG_VERSION=2019-09-06-$(PKG_SOURCE_VERSION)
PKG_VERSION=1.0

# PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_SOURCE_VERSION)

include $(INCLUDE_DIR)/package.mk

define KernelPackage/rtl8812au
  SUBMENU:=Wireless Drivers
  TITLE:=Driver for Simplecom NW601 801.11ac wireless dongle
  DEPENDS:= @USB_SUPPORT +kmod-cfg80211 +kmod-lib80211 +kmod-usb-core
  VERSION:=$(LINUX_VERSION)+$(PKG_VERSION)
  FILES:= $(PKG_BUILD_DIR)/$(PKG_NAME).ko
#  AUTOLOAD:=$(call AutoLoad,NW601_1909)
  AUTOLOAD=$(call Autoprobe,$(PKG_NAME))
endef

define KernelPackage/rtl8812au/description
  Kernel support for 802.11ac (5GHz) using SimpleCom NW601 USB dongle
endef

define Build/Compile
	echo "myDEBUG -> -----------------------------------------------------------------------" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> Build of rtl8812a (NW601) starting at `date`" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> PATH=${PATH}" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> LINUX_VERSION=$(LINUX_VERSION)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> PKG_NAME=$(PKG_NAME)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> PKG_RELEASE=$(PKG_RELEASE)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> PKG_VERSION=$(PKG_VERSION)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> PKG_SOURCE=$(PKG_SOURCE)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> PKG_SOURCE_PROTO=$(PKG_SOURCE_PROTO)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> PKG_SOURCE_URL=$(PKG_SOURCE_URL)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> PKG_SOURCE_VERSION=$(PKG_SOURCE_VERSION)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> PKG_SOURCE_SUBDIR=$(PKG_SOURCE_SUBDIR)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> PKG_BUILD_DIR=$(PKG_BUILD_DIR)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> MAKE=$(MAKE)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> KERNEL_MAKEOPTS=$(KERNEL_MAKEOPTS)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> KERNEL_MAKE_FLAGS=$(KERNEL_MAKE_FLAGS)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> KERNEL_BUILD_DIR=$(KERNEL_BUILD_DIR)" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	echo "myDEBUG -> Starting ..." >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
	$(MAKE) -d $(KERNEL_MAKEOPTS) M=$(PKG_BUILD_DIR) \
		USER_EXTRA_CFLAGS="-D_LINUX_BYTEORDER_SWAB_H -DCONFIG_BIG_ENDIAN -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT" \
		CONFIG_RTL8812A=y CONFIG_RTL8821A=y CONFIG_RTL8812AU_8821AU=m CONFIG_PLATFORM_I386_PC=n CONFIG_PLATFORM_MIPS_AR9132=y \
                src=$(PKG_BUILD_DIR) \
		modules
	echo "myDEBUG -> Finished at `date`" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
endef

$(eval $(call KernelPackage,rtl8812au))

I've added some $(info) statements to the vendor-supplied Makefile (in rtl8812au/src) to show me what's going on there. The result when I run the build is this series of trace writes. The lines beginning "echo myDEBUG" are from the 'outer' Makefile (the one I created), the lines beginning 'rtl8812uaDEBUG' are from the vendor-supplied Makefile (and yes, I know I've transposed 'ua' and 'au' in my trace write):

$ make package/kernel/rtl8812au/compile V=sc
...
echo "myDEBUG -> -----------------------------------------------------------------------" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> Build of rtl8812a (NW601) starting at `date`" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> PATH=/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/toolchain-mips_24kc_gcc-7.3.0_musl/bin:/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/toolchain-mips_24kc_gcc-7.3.0_musl/bin:/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/host/bin:/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/host/bin:/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/host/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> LINUX_VERSION=4.9.202" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> PKG_NAME=rtl8812au" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> PKG_RELEASE=1" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> PKG_VERSION=1.0" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> PKG_SOURCE=" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> PKG_SOURCE_PROTO=" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> PKG_SOURCE_URL=" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> PKG_SOURCE_VERSION=" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> PKG_SOURCE_SUBDIR=" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> PKG_BUILD_DIR=/home/jeremy/myWatt/Firmware/build_V4/openwrt/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/rtl8812au-1.0" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> MAKE=make" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> KERNEL_MAKEOPTS=-C /home/jeremy/myWatt/Firmware/build_V4/openwrt/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/linux-4.9.202 HOSTCFLAGS="-O2 -I/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/host/include -I/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/hostpkg/include -I/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/target-mips_24kc_musl/host/include -Wall -Wmissing-prototypes -Wstrict-prototypes" CROSS_COMPILE="mips-openwrt-linux-musl-" ARCH="mips" KBUILD_HAVE_NLS=no KBUILD_BUILD_USER="" KBUILD_BUILD_HOST="" KBUILD_BUILD_TIMESTAMP="Tue Nov 26 16:04:17 2019" KBUILD_BUILD_VERSION="0" HOST_LOADLIBES="-L/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/host/lib" CONFIG_SHELL="bash" V=1  cmd_syscalls= KERNELRELEASE=4.9.202 CC="mips-openwrt-linux-musl-gcc"" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> KERNEL_MAKE_FLAGS=HOSTCFLAGS="-O2 -I/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/host/include -I/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/hostpkg/include -I/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/target-mips_24kc_musl/host/include -Wall -Wmissing-prototypes -Wstrict-prototypes" CROSS_COMPILE="mips-openwrt-linux-musl-" ARCH="mips" KBUILD_HAVE_NLS=no KBUILD_BUILD_USER="" KBUILD_BUILD_HOST="" KBUILD_BUILD_TIMESTAMP="Tue Nov 26 16:04:17 2019" KBUILD_BUILD_VERSION="0" HOST_LOADLIBES="-L/home/jeremy/myWatt/Firmware/build_V4/openwrt/staging_dir/host/lib" CONFIG_SHELL="bash" V=1  cmd_syscalls= KERNELRELEASE=4.9.202" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> KERNEL_BUILD_DIR=/home/jeremy/myWatt/Firmware/build_V4/openwrt/build_dir/target-mips_24kc_musl/linux-ar71xx_generic" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
echo "myDEBUG -> Starting ..." >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log
rtl8812uaDEBUG ->  Beginning of Makefile 'configuring' section
rtl8812uaDEBUG ->  EXTRA_CFLAGS= -D_LINUX_BYTEORDER_SWAB_H -DCONFIG_BIG_ENDIAN -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -O1 -Wno-unused-variable -Wno-unused-value -Wno-unused-label -Wno-unused-parameter -Wno-unused-function -Wno-unused -Wno-date-time	 -I/home/jeremy/myWatt/Firmware/build_V4/openwrt/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/rtl8812au-1.0/include
rtl8812uaDEBUG ->  EXTRA_LDFLAGS= --strip-debug
rtl8812uaDEBUG ->  KERNELRELEASE=4.9.202
rtl8812uaDEBUG ->  End of Makefile 'configuring' section
rtl8812uaDEBUG ->  USER_MODULE_NAME=
rtl8812uaDEBUG ->  MODULE_NAME=8812au
rtl8812uaDEBUG ->  KERNELRELEASE not null
rtl8812uaDEBUG ->  At end of KERNELRELEASE not null, MODULE_NAME=8812au and obj-m=
rtl8812uaDEBUG ->  Beginning of Makefile 'configuring' section
rtl8812uaDEBUG ->  EXTRA_CFLAGS=-D_LINUX_BYTEORDER_SWAB_H -DCONFIG_BIG_ENDIAN -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT -O1 -Wno-unused-variable -Wno-unused-value -Wno-unused-label -Wno-unused-parameter -Wno-unused-function -Wno-unused -Wno-date-time	 -I/home/jeremy/myWatt/Firmware/build_V4/openwrt/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/rtl8812au-1.0/include
rtl8812uaDEBUG ->  EXTRA_LDFLAGS=--strip-debug
rtl8812uaDEBUG ->  KERNELRELEASE=4.9.202
rtl8812uaDEBUG ->  End of Makefile 'configuring' section
rtl8812uaDEBUG ->  USER_MODULE_NAME=
rtl8812uaDEBUG ->  MODULE_NAME=8812au
rtl8812uaDEBUG ->  KERNELRELEASE not null
rtl8812uaDEBUG ->  At end of KERNELRELEASE not null, MODULE_NAME=8812au and obj-m=
echo "myDEBUG -> Finished at `date`" >> /home/jeremy/myWatt/Firmware/build_V4/rtl8812_NW601.log

It's my understanding that the vendor-supplied Makefile should be invoked twice, once with KERNELRELEASE set to the Kernel version (4.9.202 in this case) and once with KERNELRELEASE not defined (or defined with no value), but the trace log shows that KERNELRELEASE=4.9.202 on both invocations.

Any suggestions?

Thanks,
Jeremy Begg

Does it compile when you invoke it manually (ie not through the buildroot)?

Hi Borromini,

Yes, it does compile outside of Buildroot.

The point of my question is, why is Buildroot not invoking the package's Makefile correctly?
I explained my understanding of how the package Makefile will be processed by Buildroot, have I not understood the process correctly? (This is my first attempt to build a driver for OpenWrt.)

Thanks

So I got it to build after realising that the driver's Makefile was not defining obj-m at all. Once I fixed that I have been able to build rtl8812au.ko and it is included in the firmware image:

root@OpenWrt:~# modinfo rtl8812au
module:		/lib/modules/4.9.205/rtl8812au.ko
license:	GPL
depends:	usbcore,cfg80211
root@OpenWrt:~# modprobe rtl8812au
1 module could not be probed
- rtl8812au
root@OpenWrt:~# 

The dongle itself shows up on the USB (device 005):

root@OpenWrt:~# lsusb
Bus 001 Device 001: ID 1d6b:0002
Bus 001 Device 003: ID 067b:2303
Bus 001 Device 002: ID 05e3:0608
Bus 001 Device 005: ID 0bda:0811

What more might I have to do to get the driver (module) to recognise the USB device and start doing something?

(As you might have guessed, this is my first attempt at building an OpenWrt kernel module/driver.)

Thanks

Check if modprobe or insmod have any verbose options (see --help). That might give you more info on why the module is not being loaded.

In a second window, keep an eye on logread (I believe the command to print new messages is logread -f).

Hi Borromini,

Thanks for the tip re modprobe and logread -f. This has given me something to trace ...

root@OpenWrt:~# modprobe rtl8812au
1 module could not be probed
- rtl8812au
root@OpenWrt:~# 

and ...

Wed Dec 11 06:26:25 2019 kern.warn kernel: [14161.833162] rtl8812au: Unknown symbol cfg80211_connect_bss (err 0)
Wed Dec 11 06:26:25 2019 kern.warn kernel: [14161.834029] rtl8812au: Unknown symbol __ieee80211_get_channel (err 0)

I will chase those down.

1 Like

Interesting. Without much knowledge of how this is supposed to work I went looking for those two symbols and where they might be defined.

cfg80211_connect_bss() is defined by cfg80211.h, of which there appear to be two variants in my OpenWrt directory tree. Variant 1 is present in these two files:

staging_dir/target-mips_24kc_musl/usr/include/mac80211/net/cfg80211.h
build_dir/target-mips_24kc_musl/linux-ar71xx_generic/backports-2017-11-01/include/net/cfg80211.h

and looks like this:

static inline void
cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
                     struct cfg80211_bss *bss, const u8 *req_ie,
                     size_t req_ie_len, const u8 *resp_ie,
                     size_t resp_ie_len, int status, gfp_t gfp,
                     enum nl80211_timeout_reason timeout_reason)
{
        struct cfg80211_connect_resp_params params;

        memset(&params, 0, sizeof(params));
        params.status = status;
        params.bssid = bssid;
        params.bss = bss;
        params.req_ie = req_ie;
        params.req_ie_len = req_ie_len;
        params.resp_ie = resp_ie;
        params.resp_ie_len = resp_ie_len;
        params.timeout_reason = timeout_reason;

        cfg80211_connect_done(dev, &params, gfp);
}

Variant 2 appears in these files:

build_dir/toolchain-mips_24kc_gcc-7.3.0_musl/linux-4.9.202/include/net/cfg80211.h
build_dir/target-mips_24kc_musl/linux-ar71xx_generic/linux-4.9.205/include/net/cfg80211.h

and looks like this:

void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
                          struct cfg80211_bss *bss, const u8 *req_ie,
                          size_t req_ie_len, const u8 *resp_ie,
                          size_t resp_ie_len, int status, gfp_t gfp);

Given the behaviour I'm seeing ("Unknown symbol") it looks like the firmware has built my driver using variant 2 but I need variant 1. (I notice variant 1 has an extra parameter in its argument list, but this shouldn't matter as the driver itself only ever calls cfg80211_connect_result(), not cfg80211_connect_bss(). In other words, the error being reported by modprobe relates to a function the driver isn't using!)

The driver source code has

#include <net/cfg80211.h>

so I'm wondering what I should change to get it to use the correct variant of cfg80211.h ?

I also noticed that variant 1 of cfg80211.h makes no reference to __ieee80211_get_channel() but variant 2 does, with a comment to the effect that it's there to be used in place of the ieee80211_get_channel() routine provided by "the ieee80211 code". (But variant 2 just declares the routine without any implementation, similar to the way it declares cfg80211_connect_bss() without any implementation.)

It's very probable that 4.9 doesn't have those symbols (or doesn't have them enabled by default). You could grep the kernel config in the buildroot for them; maybe they're there but disabled. Beyond that I can't help you myself, I am no programmer myself...

At least you know what you're looking at right now. I don't know how up to date drivers in the kernel's staging subdir need to be to be packaged along with it (I've read a few times some of them are just rotting away, basically, and that's what Realtek seems to do with their wireless drivers).