How to Create Device Node in Kernel Module
19 Mar 2018 Linux kernel HW driverDevice node is a file-like abstraction in Linux for user to interact with devices. It could map the operations (read, write, fasync etc.) performed on the file to the associated device. Otherwise, user application needs to be executed with privilege to do memory map before using the device, and programer needs to know the physical address.
After reinstall OS, the SD card reader on my laptop stops work again. Because this time I use Linux Mint, which is based on higher version kernel, I encountered more troubles to drive the SD card reader.
Three steps, five errors and solutions are recorded.
Step 1) Detect Device
Usually, SD card reader is connected to either pci bus or usb bus, so look up in the outputs of the following two command:
lspci
lsusb
What I found is:
03:00.0 Unassigned class [ff00]: Realtek Semiconductor Co., Ltd. RTS5229 PCI Express Card Reader (rev 01)
That tells me the model of the SD card reader on my laptop is RTS5229, produced by Realtek Semiconductor.
Step 2) Get Proper Driver
So I searched driver for RTS5229, and found two solutions:
Solution 1) linux-firmware-nonfree package
I learnt from this post that there is a package called linux-firmware-nonfree to drive RTS5229. While this package is not in Ubuntu 16.04 source list any longer. Although download the package then use dpkg to install it might work, it is risky to do so.
Solution 2) build from source
This is the solution which should be safer and finally works for me. But the source files I downloaded from Realtek website is for lower version of kernel. So several errors occurred when I executed sudo make
.
Werror=date-time
rts5229/rtsx.c:148:55: error: macro "__DATE__" might prevent reproducible builds [-Werror=date-time]
SPRINTF(" Build: %s, %s\n", __DATE__, __TIME__);
Compiler recognizes the warnings related to date-time as errors and prevents it from compile. Adding a flag -Wno-error=date-time
to the EXTRA_CFLAGS
variable in the Makefile can tell the compiler to ignore this error.
No rule to make target
make[2]: *** No rule to make target 'arch/x86/entry/syscalls/syscall_32.tbl', needed by 'arch/x86/entry/syscalls/../../include/generated/asm/syscalls_32.h'. Stop
This is caused by kernel that $(PWD)
does not work well in kernel header files folder. So change $(PWD)
in the Makefile to $(shell pwd)
.
unknown field
rts5229/rtsx.c:266:2: error: unknown field ‘proc_info’ specified in initializer
.proc_info = proc_info,
This field is removed away from new versions of kernel, so comment this line.
deprecated __dev… macros
rts5229/rtsx.c:914:22: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘rtsx_probe’
static int __devinit rtsx_probe(struct pci_dev *pci, const struct pci_device_idrts5229/rtsx.c:1069:23: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘rtsx_remove’
static void __devexit rtsx_remove(struct pci_dev *pci)
rts5229/rtsx.c:1095:12: error: implicit declaration of function ‘__devexit_p’ [-Werror=implicit-function-declaration]
.remove = __devexit_p(rtsx_remove)
I am using 4.10.0-38-generic, so I need to remove those macros according to the porting guide.
vmalloc header
rts5229/rtsx_chip.c:1131:16: error: implicit declaration of function ‘vmalloc’ [-Werror=implicit-function-declaration]
data = (u32 *)vmalloc(dw_len * 4);
Add #include <linux/vmalloc.h>
to the relevant files, including rtsx.c
, rtsx_chip.c
, rtsx_scsi.c
and ms.c
.
Above are all the errors I ran into.
Step 3) Install the Driver
To put the driver compiled in the second solution into use, do the following operations:
sudo make install
sudo modeprobe -r rtsx_pci
sudo depmod -a
sudo modprobe rts5229
Those commands remove the useless rtsx_pci and update module list then insert newly compiled driver.
If you are told rtsx_pci is in use and cannot be removed, unload its dependencies in order:
sudo modeprobe -r rtsx_pci_sdmmc
sudo modeprobe -r rtsx_pci_ms
To block OS from automatically selecting rtsx_pci as driver, add the following line in file /etc/modprobe.d/blacklist.conf
:
blacklist rtsx_pci
Then execute:
sudo update-initramfs -u
To verify that newly compiled driver is used, execute command:
lspci -v
And you should see the RTS5229 device information has a line:
Kernel driver in use: rts5229
If not, try restarting laptop to initialize device tree again.
Credits
- Linux: Making a system call from kernel space - Thank Pointer Overloading for a nice post about how to make system call from either user application or kernel module.
- ARM assembly under Linux - SevenMachines’ assembly code could be used as inline assembly in a user application to invoke system call.
- How is a system call executed in ARM architecture? - I gained better understanding thanks to pk007’s explaination of ARM interrupt procedure.
- How is ARM system mode different from arm supervisor mode? - Thank old_timer for explaination to distinguish System mode from Supervisor mode.
- Device node creation without using “mknod” - Thank Coherent Musings for offering a workable solution.