Logo
Graduate student at

Character device drivers

18 Mar 2026 - Tags: char-drivers

Character device drivers

Reference material

Linux kernel Character Device Drivers

Character device drivers are one kind of driver we can implement to communicate with hardware. They are abstracted as files and accessed through conventional file access system calls.

To manage these devices, the kernel uses a pair of identifiers: the a major number, to select the correct driver, and a minor number to distinguish between specific devices or modes.

A list of character and block devices in the system can be retrieved from the /proc/devices file

cat /proc/devices

File operations

Character device drivers bridge the gap between user space and the kernel by implementing functions within a struct file_operations object, which maps system calls like open, read, and write to specific kernel routines. Crucially, because kernel and user space operate in distinct memory regions with different virtual addressing, drivers cannot directly de-reference user pointers. Instead, they must use specialized functions like copy_from_user() and copy_to_user() to safely transfer data while handling potential memory faults or unallocated pages.

Example

To practice, we implemented an example called simple_char. It implements a basic character device driver that manages an internal kernel buffer. It utilizes the file_operations structure to map standard system calls—such as open, read, write, and release—to custom handler functions.

To use it we had to make the build and config steps learned in the previous tutorial:

make -C "$IIO_TREE" menuconfig

cd "$IIO_TREE"
kw build --clean

cd "$IIO_TREE"
kw build

mkdir "${VM_DIR}/arm64_rootfs"
# mount the VM `rootfs` to the given mount point in read and write mode (this could take a while)
sudo guestmount --rw --add "${VM_DIR}/arm64_img.qcow2" --mount /dev/vda2 "${VM_DIR}/arm64_rootfs" 
# install modules to inside the VM
sudo --preserve-env make -C "${IIO_TREE}" INSTALL_MOD_PATH="${VM_DIR}/arm64_rootfs" modules_install 
# unmount the VM `rootfs`
sudo guestunmount "${VM_DIR}/arm64_rootfs" 

Testing

To test what we developed, we loaded the simple_char in the vm and checked the major number to create a file to interact with our driver.

@VM
modprobe simple_char
cat /proc/devices | grep simp
239 simple_char
mknod simple_char_node c 52391 0
stat simple_char_node

A character device driver is essentially a specialized Linux Kernel Module. While a basic module might only log messages, a device driver uses the module’s initialization phase to register a device ID and map file operations (read, write) to the kernel. You use the character device interface (the node created by mknod) as a way to test and interact with our module’s logic from user space.

Then, we implemented 2 programs to read from the char device and to write to it. To use them we did the following:

@host
aarch64-linux-gnu-gcc read_prog.c -o read_prog
scp read_prog root@<VM-IP-ADDRESS>:~/
@VM
root@localhost:~# ./read_prog simple_char_node