Driver-Model

sysfs

A lot of information about the system is exported to userspace via the sysfs file system. It is usually mounted to /sys and contains the following sub-directories:

block

all block devices available in the system (hard drives, partitions, ...).

bus

bus types that are used to connect hardware devices. (pci, ide, usb, ...)

class

classes of device drivers that are available to the system. (net, sound, usb, ...)

devices

tree of devices connected to the system.

firmware

information gathered from the firmware of the system (ACPI)

module

list of currently loaded kernel modules.

Information is provided as one file per attribute. There are some standard attributes:

dev

the major- and minor-number of a block or character device. This can be used to automatically find or create the correct device node in /dev.

device

a symlink to the devices directory. This can be used to find the hardware that is used to provide some service, for example the exact PCI device of the network card eth0.

driver

a symlink to the drivers directory (located in /sys/bus/*/drivers)

A lot more attributes are available in /sys, depending on the bus and the driver used.

hotplug

Userspace programs can be started when the kernel finds new hardware devices. This can be configured via /proc/sys/kernel/hotplug. Usually a set of scripts is started that tries to find a driver which can handle the new hardware.

For example, each PCI driver can define a list of PCI vender/device IDs that it is able to handle. The device lists of all installed drivers are collected in the file /lib/modules/$kernelversion/modules.pcimap. The PCI controller calls the hotplug scripts when it finds a new PCI device. The correct driver for that hardware is looked up in modules.pcimap and loaded via modprobe. When the driver loads and detects more hardware (e.g. a disc controller enumerating all connected disk drives) then hotplug scripts may be invoked another time.

Using hotplug scripts, it is possible to autodetect most drivers that are needed in modern systems.

udev

The hotplug scripts are not limited to loading new drivers. There is a program that uses the information provided in /sys (in particular the dev attribute) to automatically create all the needed device nodes in /dev. udev hooks into the hotplug scripts to get notified when a new directory gets created in /sys.

The device node to create can be configured via some config files in /etc/udev. Please have a look at the manpages for details.

If you want to support automatic device node creation in your driver, you have to implement a dev attribute containing the major and minor number. This is described below.

Kernel infrastructure

  • struct device

  • struct bus

  • struct driver

  • struct class

How to export information from the driver

There are several possibilities to export information about your driver to userspace applications.

module parameters

All module parameters that are declared via module_param are automatically shown in /sys/module/$modulname/$paramname. The contents of the sysfs field always follows the current value of the correspondig module parameter variable. This is useful to obtain the value of some setting that may be autodetected by the module if no explicit parameter was given at module load time (e.g. for the major number or IO-base address that is to be used).

device/driver support by the bus subsystem

The kernel can detect a lot of settings automatically on most bus systems.

A PCI driver for example only has to fill in the contents of a pci_driver structure and all the rest (device creation, binding of devices and drivers, sysfs support) is automatically handled by the kernel.

class_simple

Making a driver show up correctly in sysfs using struct device/bus/driver/class can be very difficult if it is not already handled by the bus subsystem. Luckily, there is a small wrapper API that allows to publish driver information in /sys/class in a simple way: class_simple. It is mainly used to create a dev attribute which can be used by udev to automatically create device nodes for drivers.

class_simple_create(THIS_MODULE, "name")

Creates a new driver class.

class_simple_destroy(class)

removes that class.

class_simple_device_add(class, dev, device, "name%d", ...)

Add a new device entry for this class. It will automatically get a dev attribute containing the major and minor number of the device. Those numbers are both stored in the dev parameter; use MKDEV(major, minor) to get it. device points to a struct device structure if one is available; it is okay to use NULL here. The name of the new device is given with the last parameter(s); they contain one format string and an arbitrary number of format parameters, just like printk.

class_simple_device_remove(dev)

removes the device from the class, dev parameter must be the same as in device_add.

class_simple_create_file(device, attribute)

Add an extra attribute (besides the standard dev). attribute must be a pointer to a special variable which is created with the macro CLASS_DEVICE_ATTR(name, mode, show, store). This macro will create a variable class_device_attr_name representing the attribute name. It has the access mode as specified in mode (e.g. 0444 for read-only attributes). When the attribute is read or written then the show and store functions are called.

class_simple_remove_file(device, attribute)

remove an attribute from a device.