1. Devices and Device Files
In Linux, the kernel manages various hardware devices or virtual devices through drivers, for example:
- Serial port controller
- GPIO controller
- Random number generator
- Storage controller
- Display controller, etc.
User space programs do not directly operate hardware registers but access devices through unified interfaces provided by the kernel.
As we discussed in previous chapters, these are device files (device file), usually located in the /dev directory.
Execute on the development board:
ls -l /devYou can see something like:
crw-rw-rw- 1 root root 1, 3 Dec 9 19:02 null
crw-rw---- 1 root tty 4, 0 Dec 9 19:02 tty0
brw-rw---- 1 root disk 179, 0 Dec 9 19:02 mmcblk02
3
These entries are not ordinary disk files but "access entry points for devices". User space indirectly accesses actual devices by performing open / read / write / ioctl and other operations on these device files.
2. Basic Classification of Character Devices and Block Devices
From the perspective of "access method", Linux roughly divides devices into two categories:
- Character Device (Character Device)
- Block Device (Block Device)
In /dev, you can distinguish through the first character of the first column in ls -l output:
- Starting with
c: character device (character) - Starting with
b: block device (block)
Example:
crw-rw-rw- 1 root root 1, 3 ... null # Character device
brw-rw---- 1 root disk 179, 0 ... mmcblk0 # Block device2
1. Character Device
Character Device (Character Device) provides access interface in the form of byte stream. Its characteristics include:
- Read and write data byte by byte (or byte sequence), similar to streaming I/O.
- Usually does not require alignment to fixed-size data blocks.
- Suitable for various control-type devices or streaming data devices.
Typical examples:
- Serial port terminal:
/dev/ttyS0,/dev/ttyS1, etc. - Console:
/dev/console - Random number device:
/dev/random,/dev/urandom - Virtual device:
/dev/null,/dev/zero - GPIO / I2C / SPI control interfaces are also presented as character devices on many systems
- User-defined character devices: such as
/dev/mychar, etc.
User space accessing character device example:
int fd = open("/dev/ttyS0", O_RDWR);
write(fd, buf, len);
read(fd, buf, len);
close(fd);2
3
4
In the kernel, such devices are usually implemented by character device drivers, responding to the above system calls through a set of callback functions (file_operations).
2. Block Device
Block Device (Block Device) is accessed in fixed-size data blocks, such as 512 bytes, 4 KB, etc. Its characteristics include:
- Supports efficient random access and caching mechanisms.
- Mainly used for various persistent storage media.
Typical examples:
- eMMC / SD card:
/dev/mmcblk0,/dev/mmcblk0p1, etc. - USB drive, SATA/USB disk:
/dev/sda,/dev/sdb - Compressed memory block device:
/dev/zram0, etc.
Block devices are usually not directly accessed by applications in frequent "raw block" form. Instead:
- Create a file system (such as ext4, vfat, etc.) on it;
- Mount that block device to a directory;
- Access files in the file system through ordinary file read/write interfaces.
Block device drivers work with file systems and are relatively complex, so we won't expand on them here.
3. Why Focus on Learning Character Device Drivers
In Linux driver development, there are various types of drivers:
- Character device driver
- Block device driver
- Network device driver
- Input subsystem driver (keyboard, touchscreen, etc.)
- Sound subsystem driver (ALSA)
- Graphics / display driver, etc.
For beginners, starting with character device drivers has the following advantages:
- Intuitive interface form The operation interfaces used by character devices are similar to ordinary files, including:
openreadwriteioctlclose, etc. These interfaces are also frequently used in user space programming, making them easy to understand.
- Simple debugging method Once a node is established under
/dev, you can directly:echo/cathexdump- Simple C test programs Perform read/write operations on the device to verify driver logic.
- Wide Applicability Many simple or medium-complexity peripherals can be encapsulated through the character device model, for example:
- GPIO control
- Simple sensors
- LED control
- Virtual test devices, etc.
Therefore, this chapter will expand on the basic concepts and implementation methods of character devices, including:
- Application and management of device numbers
- Character device framework (
cdev/miscdevice, etc.) - Creation of device nodes (
/dev/mychar) - Data exchange methods between user applications and drivers, etc.
4. Interface: file_operations
When user space accesses device files, standard system calls are used:
open()/close()read()/write()ioctl(), etc.
After receiving these calls, the kernel needs to hand them over to specific device drivers for processing. In character devices, this process is mainly completed through struct file_operations.
In a typical character device driver, you would define a structure like this:
static const struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = my_open,
.release = my_release,
.read = my_read,
.write = my_write,
.unlocked_ioctl = my_ioctl,
};2
3
4
5
6
7
8
The meaning can be simply understood as:
- When user space calls
open()on/dev/mychar, the kernel callsmy_open()in the driver. - When
read()is called, it entersmy_read(). - When
write()is called, it entersmy_write(). - When
ioctl()is called, it entersmy_ioctl().
Therefore, from the kernel implementation perspective:
Character device driver = a set of
**file_operations** callback functions + device number registration + binding with**/dev** device node.