Main Content
1. sysfs and kobject
2. device-bus-driver
2.1 bus_type
2.2 class and device_type
2.3 device/driver and sysfs
2.4 device and driver matching
This article is based on the analysis of Linux version 6.6.92
1. sysfs and kobject
sysfs is a virtual file system in the Linux kernel, its main function is to provide a unified interface for user space to access kernel data, allowing users to view and modify information about devices and drivers
sysfs organizes devices and buses connected to the system into a hierarchical file structure, which can be accessed from user space, typically mounted under the /sys directory
$ ls /sys
block class devices fs kernel pmic_info systeminfo
bus dev firmware io_log_data module power vservices
kobject serves as a bridge between device drivers and sysfs:kobject corresponds to a directory in sysfs
- • parent points to the parent kobject
- • sd points to kernfs_node, which is the carrier (implementation) of the sysfs file system directory
kset is a collection of kobjects
- • list is a linked list connecting its own kobjects
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/af722992-53ad-41a6-85f9-d9ae94a712e0.png)
kobject_create_and_add() function creates and initializes a kobject {} object, then calls kobject_add() to add it to the system
kobject_add() function is quite complex, the main logic is as follows
- • Set the name and parent of the kobject
- • If a kset is specified, add it to the end of the kset’s list
- • Then create directories and attribute files
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/14679bed-c855-4343-95c5-e3be80bd9cdb.png)
kset_create_and_add() is used to create and initialize a kset {} object, then calls kset_register() to add it to the system
kset_register() function does two things
- • Calls kobject_add_internal() to add kset::kobj to the system
- • Then sends a uevent to the system
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/77b10485-5e73-41e4-9c03-dbfc8142a4de.png)
2. device-bus-driver
During initialization, the buses_init() and devices_init() functions create the bus/class/dev/devices directories under the “/sys” directory
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/2e632633-6cec-4d61-b330-08d46fdc3ade.png)
2.1 bus_type
The system uses the bus_type {} data structure to represent a bus, for example, platform_bus is defined as follows
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match,
.uevent = platform_uevent,
.probe = platform_probe,
.remove = platform_remove,
.shutdown = platform_shutdown,
.dma_configure = platform_dma_configure,
.dma_cleanup = platform_dma_cleanup,
.pm = &platform_dev_pm_ops,
};
More information is in the subsys_private {} data structure, where a subsys_private {} object is allocated in the bus_register() function
- • bus points to the bus_type {} object
- • subsys is a kset {} object, which will create a directory /sys/bus/busX
- • device_kset and driver_kset are used to manage the kobjects of devices and drivers on the bus
- • The kobjects of devices and drivers are added to device_kset and driver_kset respectively
- • klist_devices and klist_drivers linked lists are used to connect devices and drivers on the bus
- • The interfaces linked list connects subsys_interface {} objects, notifying the corresponding bus_type {} object when devices are added and removed
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/0c4f4da7-3d7a-47e6-a6f8-714436e92abd.png)
The bus_register() function adds a bus_type {} object to the system
- • Allocates a subsys_private {} object
- • Creates the “/sys/bus/busX” directory
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/011ea644-e0f0-43c1-9fa6-256f50b40d2a.png)
For example, the contents under the “/sys/bus/platform” directory
$ ls /sys/bus/platform/
devices drivers drivers_autoprobe drivers_probe uevent
2.2 class and device_type
class provides device category information for user space, used to organize devices under “/sys/class” for easier management
device_type is the category information of the device model, mainly used to provide common kernel callbacks, kobject/sysfs attribute groups, uevent handling, etc., for the same kernel device type. It is more related to kernel implementation/behavior.
The class {} object is also bound to a subsys_private {} object
- • The interfaces linked list connects class_interface {} objects, used to notify devices when adding and removing
- • The klist_devices linked list connects all devices of the current class
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/dacd1942-73f2-4fd6-8dbc-237cde1b48fb.png)
class_register() function registers a class, creating a directory cls->name under /sys/class
If class_groups is specified, attribute files will be created under /sys/class/cls->name/
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/ef781ca5-b73c-4406-a6a1-5be736474fe3.png)
For example, when a character device calls the device_get_devnode() function to get the node name
- • It first tries to use the devnode in device_type to get the node name
- • If not supported, it tries to use the function callback pointed to by devnode in class to get the node name
- • Finally, it uses dev_name() as the node name
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/a06a3369-7314-435d-afae-675fa4354997.png)
2.3 device/driver and sysfs
When adding a device {} object, directories and files are created in the sys file directory, below is the creation of the sound card
- • uevent file
- • device links to parent
- • subsystem links to class
- • A link is also established in the class directory
$ pwd
/sys/class/sound
$ ls -la pcmC0D0p
lrwxrwxrwx 1 root root 0 2025-11-24 20:54 pcmC0D0p -> ../../devices/platform/soc/soc:qcom,msm-audio-apr/soc:qcom,msm-audio-apr:qcom,q6core-audio/soc:qcom,msm-audio-apr:qcom,q6core-audio:sound/sound/card0/pcmC0D0p
$ pwd
/sys/devices/platform/soc/soc:qcom,msm-audio-apr/soc:qcom,msm-audio-apr:qcom,q6core-audio/soc:qcom,msm-audio-apr:qcom,q6core-audio:sound/sound/card0
$ ls -la pcmC0D0p
total 0
drwxr-xr-x 3 root root 0 2025-11-24 21:52 .
drwxr-xr-x 121 root root 0 2025-11-24 21:51 ..-????????? ? ? ? ? ? dev
lrwxrwxrwx 1 root root 0 2025-11-24 21:52 device -> ../../card0
-????????? ? ? ? ? ? pcm_class
drwxr-xr-x 2 root root 0 2025-11-24 21:52 power
lrwxrwxrwx 1 root root 0 2025-11-24 21:52 subsystem -> ../../../../../../../../../class/sound
-????????? ? ? ? ? ? uevent
The function calls are as follows
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/d871f993-cbf9-458a-9581-7127a235d319.png)
Additionally, there are defined attributes, for example, the three attributes defined by v4l2
static DEVICE_ATTR_RO(index);
static DEVICE_ATTR_RW(dev_debug);
static DEVICE_ATTR_RO(name);
static struct attribute *video_device_attrs[] = {
&dev_attr_name.attr,
&dev_attr_dev_debug.attr,
&dev_attr_index.attr,
NULL,
};
ATTRIBUTE_GROUPS(video_device);
static struct class video_class = {
.name = VIDEO_NAME,
.dev_groups = video_device_groups,
};
In the directory corresponding to the device, three corresponding files will be created
$ pwd
/sys/devices/platform/cam_sync/video4linux/video1
$ ls -la
total 0
drwxr-xr-x 3 root root 0 2025-11-24 21:17 .
drwxr-xr-x 3 root root 0 2025-11-24 21:17 ..-????????? ? ? ? ? ? dev
-????????? ? ? ? ? ? dev_debug
lrwxrwxrwx 1 root root 0 2025-11-24 21:17 device -> ../../../cam_sync
-????????? ? ? ? ? ? index
-????????? ? ? ? ? ? name
drwxr-xr-x 2 root root 0 2025-11-24 21:17 power
lrwxrwxrwx 1 root root 0 2025-11-24 21:17 subsystem -> ../../../../../class/video4linux
-????????? ? ? ? ? ? uevent
$ pwd
/sys/devices/platform/cam_sync/video4linux
$ ls -la /sys/bus/platform/devices/ | grep cam_sy
lrwxrwxrwx 1 root root 0 2025-11-24 21:56 cam_sync -> ../../../devices/platform/cam_sync
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/abb75133-27d4-4fce-9d35-5e99c6569522.png)
Finally, the files and directories created by the driver in sysfs
$ pwd
/sys/devices/platform/snd-soc-dummy
$ ls -la
total 0
drwxr-xr-x 3 root root 0 2025-11-25 00:25 .
drwxr-xr-x 23 root root 0 1972-07-19 02:27 ..lrwxrwxrwx 1 root root 0 2025-11-25 00:26 driver -> ../../../bus/platform/drivers/snd-soc-dummy
-????????? ? ? ? ? ? driver_override
-????????? ? ? ? ? ? modalias
drwxr-xr-x 2 root root 0 2025-11-25 00:26 power
lrwxrwxrwx 1 root root 0 2025-11-25 00:26 subsystem -> ../../../bus/platform
-????????? ? ? ? ? ? uevent
$ ls -la ../../../bus/platform/drivers/snd-soc-dummy
total 0
drwxr-xr-x 2 root root 0 2025-11-25 00:26 .
drwxr-xr-x 310 root root 0 2025-11-25 00:26 ..-????????? ? ? ? ? ? bind
lrwxrwxrwx 1 root root 0 2025-11-25 00:26 snd-soc-dummy -> ../../../../devices/platform/snd-soc-dummy
-????????? ? ? ? ? ? uevent
-????????? ? ? ? ? ? unbind
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/f0a3ffab-3cb5-44f6-817f-a945edfbcfb0.png)
2.4 device and driver matching
device {} objects are bound to a device_private {} object, similarly, device_driver {} objects are also bound to a device_private {} object
In device_private, the klist_children linked list connects all child devices
In driver_private, the klist_devices linked list connects all matched devices
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/76ff5ce0-3b75-4368-8113-48edaecbd0d2.png)
device_register() function is used to add a device to the system: first calls device_initialize() to initialize, then calls device_add() to add the device
device_add() function will call bus_probe_device() to match with the driver
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/12cc31f3-99a5-4aee-8f56-451b72d0ba84.png)
bus_probe_device() function
- • If dev->driver is not null, add the device to the driver’s klist_devices linked list
- • Then traverse the bus’s klist_drivers linked list, trying to match the device and driver
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/944a5be8-d3e7-45f3-9610-c3ad821a48b7.png)
driver_register() is used to add a driver {} object
- • Adds itself to the bus’s klist_drivers linked list
- • Traverses the bus’s klist_devices linked list, trying to match
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/ae9e3f43-5d59-41d7-8428-0a004cdf6926.png)
If the device and driver match successfully, the probe function is called
This is a simplification and does not consider asynchronous behavior; refer to the source code for more details
![[LNX007] Linux Device Driver Model: Device-Bus-Driver](https://boardor.com/wp-content/uploads/2026/01/618e4675-8b9b-45a1-a442-9a8027c26261.png)