Unofficial
On this page
  1. 01What the workshop does
  2. 02Prepare the workspace
  3. 03The project
  4. 04Build the driver
  5. 05Check it against the running kernel
  6. 06Load it, and what that means

Build a kernel module for your NAS: the CH341 USB-serial driver

Many USB-serial adapters with a CH340 or CH341 chip need the kernel's ch341 driver. The QTS 6.1 NAS shown here does not ship it. The kernel workshop of Bucket & Code Server IDE builds such a module for the kernel the NAS runs, checks it against that kernel and loads it.

  1. Profilewhat the kernel is
  2. Workspacea tree configured to match
  3. Builddrivers/usb/serial
  4. Checkvermagic, layout, symbols
  5. Loadan admin's, at your risk

The pictures come from a NAS with QTS 6.1 and kernel 6.6.129-qnap, with each field filled in as this guide describes.

01What the workshop does

QNAP's public GPL archive lists kernel source through QTS 5.2.3, without the kernel running on this QTS 6.1 NAS. The workshop therefore reads what the running kernel shows about itself and configures a kernel tree from kernel.org to match it. The Kernels page shows that profile: the release, the compiler QNAP used, the vermagic and the layout of struct module in QNAP's own modules, and whether modules must be signed.

Running kernel: release 6.6.129-qnap, x86_64 TS-X74P, compiler x86_64-QNAP_gcc13-linux-gnu-gcc 13.2.0, binutils 2.41, vermagic 6.6.129-qnap SMP preempt mod_unload, struct module 1152 bytes with init at 312 and exit at 1064, QNAP's modules carry no signature, read from QNAP's own modules
  • You need the Kernel builder environment from the Examples gallery (Apps → Examples): Ubuntu 24.04 with GCC 13 and the kernel build tools. The workshop requires the same GCC major version as the running kernel and checks it before preparing the workspace.
  • Preparing, building and loading are an admin's; checking is a developer's. In the editor's terminal, which is root, the same steps are bvs kernel commands.

02Prepare the workspace

The workspace is a kernel tree for exactly the running kernel, in kernels/<release> of the data folder. On the Kernels page press Prepare the workspace:

  1. Source: leave the suggested one. For 6.6.129 it is the tree from kernel.org, since QNAP's own trees hold only older kernels. Kernel sources: Linux 6.6.129 from kernel.org, suggested, holds this kernel, 134 MB downloaded; QNAP's GPL source of QTS 5.2.3 with kernels 5.10.60, 4.14.24 and 4.2.8, another version, 780 MB
  2. Environment: kernel-builder. Extra settings, one per line: USB_SERIAL=m and USB_SERIAL_CH341=m, the USB-serial core and the CH341 driver. Leave Build the whole kernel off, then press Prepare. Prepare the workspace of 6.6.129-qnap: Source the suggested one, Environment kernel-builder, Extra settings USB_SERIAL=m and USB_SERIAL_CH341=m, Build the whole kernel unticked, and the Prepare button
  3. A job unpacks the source, configures it from the profile and your settings, prepares it for module builds and checks that the tree builds for exactly the running release. The Workspace card says ready. A failed prepare keeps the previous tree. Workspace, ready: source linux-6.6.129 from kernel.org, configuration defconfig+profile with USB_SERIAL=m and USB_SERIAL_CH341=m, environment kernel-builder, and the Build modules and Delete buttons

03The project

New project has two templates under Kernel: a hello module of your own, and the ch341 driver. Choose USB serial driver ch341.

New project's Kernel templates: Kernel module, a hello kernel module with Kbuild and a Makefile; USB serial driver ch341, the kernel's own ch341 driver for CH340 and CH341 USB-serial adapters, chosen

The project holds a Makefile whose targets are the workshop's commands, and a workflow for the NAS's runner:

# the project's Makefile, run as root in the editor's terminal
make prepare   # bvs kernel prepare --option USB_SERIAL=m --option USB_SERIAL_CH341=m
make           # bvs kernel make --dir drivers/usb/serial
make check     # bvs kernel check ch341
make load      # bvs kernel load ch341
make unload    # bvs kernel unload ch341

At every push the workflow builds the driver with --build-only and checks it. That build's ch341.ko goes to the run's artifact modules, never into the workspace, so the module make load loads stays the one you built.

04Build the driver

On the Kernels page, Build modules builds a project's folder or a directory of the kernel tree. The ch341 driver is part of the tree: choose A directory of the kernel tree and type drivers/usb/serial. make in the project does the same.

Build modules in 6.6.129-qnap: What to build, A directory of the kernel tree; Directory drivers/usb/serial; Targets left empty; and the Build button

The build makes ch341.ko and usbserial.ko. The workspace keeps ch341.ko in its modules/. It does not keep usbserial.ko, because QNAP ships that one and QNAP's copy is the one that loads.

Modules of the workspace: bvs_hello and ch341, both not loaded, with their size, the date they were built, and the Check and Load buttons

05Check it against the running kernel

Check compares the module with the running kernel: the vermagic, the size of struct module and where init and exit sit in it, whether a signature is required, the modules it depends on, and every symbol it needs. Each finding says what does not match and what to do.

Check of ch341: loadable; a warning that 2 symbols, jiffies and kmalloc_caches, cannot be looked up because this kernel lists no data symbols, and that the kernel refuses the module at load if it lacks one of them

QNAP's kernel does not list its data symbols, so the check names symbols such as jiffies as warnings. On the command line, bvs kernel check ch341 ends with exit status 3 when the module must not be loaded.

06Load it, and what that means

A module runs inside the kernel with every right the kernel has. A faulty one can stop the NAS. Load only what you built for a reason, and only on a NAS you can restart.

  • Load (admin), or make load, runs the check again and loads the module, the modules it depends on first: here QNAP's usbserial. A module with an error in the check is never loaded. Unload removes it; a module in use stays loaded. Every load and unload is written to log/kernel-modules.log.
  • A module you load by hand is gone after a restart. To have it at every start, name it in an App Builder app's kernel modules: activating the app loads it, and every start of the package loads it again.
  • If the NAS stopped without the package's ordered stop (a crash, a power cut, a hard reset) in a boot in which the package loaded modules, the next start leaves those modules out, since one of them may have caused the crash, and a notice names them. Loading one by hand, or activating its app again, lets the start load it again.
  • After a QTS update to another kernel, prepare that kernel's workspace and build the module again. A backup does not hold kernels/.