question

smoothfroggy avatar image
smoothfroggy asked

Venus OS / RaspberryPi / Compile a kernel driver module

Dear all,

I would like to request help and advices on how to compile a specific driver kernel module on Venus.

I have a Usb2CanV2.0 interface from IXXAT and already successfully compiled and operated the socketcan driver on a regular Debian (Linux 4.9) as well as the latest Raspbian (Linux >5.6).
Data about this product and driver source can be found as follows:
- https://www.ixxat.com/products/products-industrial/can-interfaces/usb-can-interfaces/usb-to-can-v2-professional?ordercode=1.01.0281.12001
- https://cdn.hms-networks.com/docs/librariesprovider8/ixxat-english-new/pc-can-interfaces/linux-drivers/socketcan-linux.zip?sfvrsn=3eb48d7_10

In order to compile for Venus (installed on a RaspberryPi V3B+), I have downloaded and installed the SDK according to instructions provided (https://github.com/victronenergy/venus/wiki/howto-install-and-use-the-sdk) and tested compilation and execution of the 'helloworld.c' test code.

My main issues regarding the compilatoin of the kernel module are the modification of the MakeFile and the location of the usual kernel headers for venus:

  • Calling make as usual enter path '/usr/src/linux-headers-4.9.0-9-amd64' rather than '/opt/venus/current/sysroots/cortexa7hf-neon-vfpv4-ve-linux-gnueabi' and calls the host linux gcc and libs rather than the SDK toolchain...
  • Trying to compile directly throw errors:
$CC ixx_usb_v2.c

ixx_usb_v2.c:18:10: fatal error: linux/usb.h: No such file or directory
 #include <linux/usb.h>
          ^~~~~~~~~~~~~
compilation terminated

Trying to locate the usb.h thanks to a classic find command was unsuccessful : ./usr/include/pcap/usb.h which has nothing to do with the necessary one linux/usb.h

For information, here is the Makefile

mod-name += ixx_usb
obj-m += ixx_usb.o
ixx_usb-objs := ixx_usb_v2.o ixx_usb_fd.o ixx_usb_core.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
install:
    mkdir -p /lib/modules/$(shell uname -r)/kernel/drivers/net/can/usb/ixxat/
    install $(mod-name).ko /lib/modules/$(shell uname -r)/kernel/drivers/net/can/usb/ixxat/
    depmod -a
    modprobe $(mod-name)    
uninstall:
    rm -f /lib/modules/$(shell uname -r)/kernel/drivers/net/can/usb/ixxat/$(mod-name).ko
    modprobe -r $(mod-name)
    depmod -a


I would be very grateful if someone (maybe @mvader (Victron Energy)) could provide some guidance on how to progress on this subject.

Best regards,

Xavier

Venus OS
2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

2 Answers
daryl avatar image
daryl answered ·

Try posting in the modifications space - https://community.victronenergy.com/spaces/31/index.html

2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

Radu - Eosif Mihăilescu avatar image
Radu - Eosif Mihăilescu answered ·

This is what worked for me:

  1. log onto the target (a CCGX, in my case; see instructions) and find out the current kernel version by running uname -rWe'll assume this has been stored in the $UNAME_R variable on the host (i.e. your PC)
  2. look onto the host (your PC) and identify the cross compiling prefix of your ARM toolchain. For example, if your ARM C compiler is called arm-linux-gnu-gcc, the prefix is arm-linux-gnu- (note the trailing dash). We'll assume this has been stored in the $CROSS_P variable on the host
  3. fetch the kernel source for the target machine and correct version from https://github.com/victronenergy/linux/archive/refs/tags/v${UNAME_R}.tar.gz into a folder of your choice (that is on a file system that has enough free space for compilation, around 2GB in my case)
  4. unpack the downloaded source by running tar zxf v${UNAME_R}.tar.gz (this should create a new folder called linux-${UNAME_R})
  5. change to the said new folder and initialize the kernel configuration from the same default one that Victron uses. In the case of the CCGX, that's ccgx_defconfig. There appear to also be canvu500_defconfig and sunxi_victron_defconfig that may apply to other GX machines. The command to run is make ARCH=arm CROSS_COMPILE=$CROSS_P ccgx_defconfig
  6. enter the kernel configuration UI by running make ARCH=arm menuconfiggo to General setup -> Local version and type in the part after the numbers in $UNAME_R. For example, if $UNAME_R is 1.2.34-foobar, then fill in -foobar (note the leading dash). This is important, as the target will refuse to load modules that do not have the exact same version string as the kernel it currently runs!
  7. go through the configuration UI and enable the modules you want compiled. It is also very important not to change anything that's built into the kernel (or that influences its exported API) so that the modules you get from this procedure can actually load and run on the target with no issues
  8. when happy, exit the configuration UI and save the configuration when asked
  9. compile the kernel in order for the exported API symbol table to be generated (yes, it would be nice if this could be generated by static analysis of the sources but at the time of this writing we don't have that). You will not be using the resulting kernel image, but the module compilation uses information generated by this step. The command to run is make -j$(nproc) ARCH=arm CROSS_COMPILE=$CROSS_P zImage
  10. at this point you need to decide whether you just want one module (or a small number of related modules), whether it's easier to just compile all modules and pick from them afterwards or whether you actually want to compile an out-of-tree module against the sources prepared so far
    • for one module (or a small related set), run make ARCH=arm CROSS_COMPILE=$CROSS_P -C . M=<relative path to module folder>
    • for all modules, run make -j$(nproc) ARCH=arm CROSS_COMPILE=$CROSS_P modules
    • for an out-of-tree module, see its documentation and point it to these kernel sources. Depending on the situation, you may need to manually give it the version ($UNAME_R) and the cross-compiling prefix ($CROSS_P) as well. Some modules may use in-kernel APIs that are not exported by the kernel as built for the target and thus they will either not compile or not work on the target
  11. do a module installation to post-process and extract them from the source tree to a convenient location. This differs depending on your choice above:
    • for one or all modules, run mkdir -p ../venus-modules_$UNAME_R &&\
      make ARCH=arm INSTALL_MOD_PATH=../venus-modules_$UNAME_R modules_install
      where ../venus-modules_$UNAME_R was the chosen target folder for the module installation -- you can pick your own name for it
    • for an out-of-tree module, see its documentation again. Some will also use modules_install, some will require different commands to post-process and give you the usable module
  12. pick the wanted module(s) from the installation directory above and copy them over to the target (e.g. with scp). It's probably a good idea not to overwrite any of the factory modules and to create a folder under /lib/modules/$UNAME_R on the target and leave them there. Note that the actual directory structure doesn't matter as depmod and modprobe are only looking at the files themselves, not the folders they are in
  13. refresh the module dependency information on the target by running depmod -a there
  14. that's it! You can now either manually modprobe the new modules, or connect the new device and have udev automatically do that for you
2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

Related Resources