Hardware initialisation and Device Driver Loading using udev.



This is probably out of date now... I wrote it to get some things clear in my head....

The Summary below gives an overview of the process that takes place when a device is configured using udevd. For each numbered section in the summary there is a link to longer sections ( below the summary ) which go into greater detail.

Summary.

[1] H/W is plugged in.

[2] kernel creates a "uevent" for the udev daemon (/sbin/udevd)
and configures sysfs (/sys) entries.

[3] udevd calls /sbin/hwup to load driver module and initialise device

[4a] /sbin/hwup reads device specific config file from /sysconfig/hardware/<config>
[4b] If no such config file exists uses sysfs (/sys/... ) to find modalias

[5] Module configuration info is passed back to the udevd.

[6] udevd calls /sbin/modprobe to load driver module. if hwup used step [4b] modprobe will use modalias to find correct module from /etc/modules/<kernel_version>/modules.aliases

[7] udevd creates device files according to contents of /etc/udev/rules.d/
     udev informs applications of the new device through the Hardware Abstraction Layer ( HAL )


Long Version.

[1] Hardware is plugged in an noticed by the kernel ( expansion bus drivers make kernel aware (?) )


[2] Kernel creates an "uevent" for the udev daemon.

/sbin/udevd which is started from /etc/init.d/boot.d/S03boot.udev.
At start time the udevd daemon created static devices using the following command :-

/sbin/udev.create_static_devices.sh /etc/udev/static_devices.txt

/sbin/udevd also checks to see if the kernel was compiled with the KOBJECT_UEVENT system variable set and if so enables uevent messaging. if not it uses :/sbin/udevsend and configures this by:-

echo "/sbin/udevsend" > /proc/sys/kernel/hotplug

and udevd is NOT started.

Kernel uevents and udevd activity can be monitored with /usr/sbin/udevmonitor ( must be root ) , included in the output is the device path of the newly :added / removed hardware.


[3] udevd calls /sbin/hwup to load driver module and initialise device.
hwup is called with the hardware descripton as an argument e.g

 hwup bus-pci-0000:01:00.0

( Use /sbin/lspci to show pci bus paths for different devices. hwdown <h/w_desc> can be used to stop a device ( leaving the module still inserted .) and :similiarly hwstatus <h/w_desc> reports on modules used for a device.)


[4a] /sbin/hwup uses this hardware descriptor argument to read a specific config file from /sysconfig/hardware/

 pjohnson@osslin7:/dev> ls /etc/sysconfig/hardware
 config  hwcfg-bus-pci-0000:00:1f.5  hwcfg-bus-pci-0000:01:00.0  hwcfg-static-printer

The filenames follow a pattern by which the hwup command can identify a config file that relates to a specific piece of hardware. The contents of this :config file are then used to find a device driver module.

 pjohnson@osslin7:/etc/sysconfig/hardware> cat hwcfg-bus-pci-0000:01:00.0
 MODULE='tg3'
 MODULE_OPTIONS=''
 STARTMODE='auto'

This module information is then passed back to the udev daemon.

[4b] If there is no such config file as described in section [4a] hwup uses the kernel provided "sysfs" (/sys/.... ) to retrieve information describing :the hardware so that the correct module can be loaded.

 ls /sys/bus/pci/devices/
 .   0000:00:00.0  0000:00:03.0  0000:00:1d.0  0000:00: 1d.2  0000:00:1d.7  0000:00:1f.0  0000:00:1f.2  0000:01:00.0
 ..  0000:00:02.0  0000:00:04.0  0000:00:1d.1  0000:00:1d.3  0000:00:1e.0  0000:00:1f.1  0000:00: 1f.5  0000:40:00.0

( Again, you can use /sbin/lspci to see what devices are connected to your pci bus. )

 osslin7:/sys/bus/ide/devices # ls
 0.0  1.0

If we look at the contents of one device's directory ( in this case the network card )

 osslin7:/sys/bus/pci/devices/0000:01:00.0 # ls
 bus  class  config  device  driver  irq  local_cpus  modalias  power  resource  resource0  subsystem_device  subsystem_vendor  vendor

Certain hardware identifiers have been taken from the card and placed into files ( within the sysfs filesystem ) such as the hex vendor and device :identifiers. ( all PCI vendor IDs can be found under http://pci-ids.ucw.cz/iii/ )

The bus type , vendor , device and unique part identifiers are put together to create the modalias string which uniquely identifies the device and it's :make / model / version.

 osslin7:/sys/bus/pci/devices/0000:01:00.0 # cat modalias
 pci:v000014E4d00001677sv0000103Csd000012F2bc02sc00i00

This modalias string is returned back to the udev daemon so that the correct driver module can be loaded.


[5] Module configuration info is passed back to the udevd by hwup. ( this step is only to show that it is udevd that is running the show, not hwup.)


[6] udevd calls /sbin/modprobe to load driver module.

first a little about modprobe as it's important.

modprobe is used to load driver modules into the kernel. It's use is preferable over /sbin/insmod as it automatically resolves module dependencies ( as :listed in the /lib/modules/<kernel>/modules.dep file , which is created by the /sbin/depmod command.) }--

if hwup used step [4b] modprobe will use the modalias string provided by hwup to find correct module from /lib/modules/<kernel_version>/modules.aliases e.g

Remind ourselves of our modalias string for our network card.

 cat /sys/bus/pci/devices/0000\:01\:00.0/modalias
 pci:v000014E4d00001677sv0000103Csd000012F2bc02sc00i00

The vendor and device type portion of this string point to one module from the modules.alias file ( luckily the same module (tg3) as specified in the :/etc/sysconfig/hardware/hwcfg-bus-pci-0000:01: 00.0 file!.)

 grep   v000014E4d00001677   /lib/modules/2.6.13-15.12-smp/modules.alias
 alias pci:v000014E4d00001677sv*sd*bc*sc*i* tg3

modprobe then loads the module taking into account settings from /etc/modprobe.conf

/etc/modprobe.conf defines options and aliases for modules that are to be loaded. it also "includes" the contents of /etc/modprobe.conf.local and :/etc/modprobe.d

also local changes should be made to /etc/modprobe.conf.local ( as they may otherwise be overwritten by patching.)

The config files can also be used to "blacklist" a module , i.e prevent it from being loaded.


[7] udevd creates /device tree and /dev tree device files for the newly configured hardware according to contents of /etc/udev/rules.d/*

 unixspod@osslin5:/etc/udev/rules.d> ls
 05-udev-early.rules            40-alsa.rules          60-cdrom_id.rules            65-cdrom.rules             85-mount-fstab.rules
 29-net_trigger_firmware.rules  50-udev-default.rules  60-persistent-input.rules    71-multipath.rules         90-hal.rules
 30-net_persistent_names.rules  51-lirc.rules          60-persistent-storage.rules  72-multipath-compat.rules  95-udev-late.rules
 31-network.rules               56-idedma.rules        64-device-mapper.rules       80-sysconfig.rules

The rules scripts are processed in order of the shell expansion , i.e in their numbered order. Many rules scripts provide persistent names so that :persistent device names remain regardless of the order in which devices are configured.

For example:-

Persistent storage device names are created.

The device names /dev/hda /dev/hdb etc.. are assigned simply in the order they are discovered / configured. This is vulnerable to a hardware :reconfiguration ( say the inroduction of a IDE controller card ) which would affect the order of device discovery. To offer a solution to this problem :device files are also created that include disk specific device names. In the case of disks these device files can be found under /dev/disk

 unixspod@osslin5:/> ls /dev/disk
 by-id  by-path  by-uuid

Where:-

by-id contains device filenames based on the Vendor and Name of a device.
by-path contains device filenames based on the bus position / path of a device.
by-uuid contain device filenames based on the serial number of a device.

Here are some rules that create the by-id device filenames for ata drives.

<extract from /etc/udev/rules.d/60-persistent-storage.rules>
 # by-id (hardware serial number)
 KERNEL=="hd*[!0-9]", IMPORT{program}="ata_id --export $tempnode"
 KERNEL=="hd*[!0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/ata-$env{ID_MODEL}_$env{ID_SERIAL}"
 KERNEL=="hd*[0-9]", SYMLINK+="disk/by-id/ata-$env{ID_MODEL}_$env{ID_SERIAL}-part%n"

And here are the device filenames created ( together with their links to the plain device names. )

 unixspod@osslin5:/> ls -l /dev/disk/by-id/
 lrwxrwxrwx 1 root root  9 May 15 20:04 ata-WDC_WD800BB-75CAA0_WD-WMA8E8009441 -> ../../hda
 lrwxrwxrwx 1 root root 10 May 15 20:04 ata-WDC_WD800BB-75CAA0_WD-WMA8E8009441-part1 -> ../../hda1
 lrwxrwxrwx 1 root root  9 May 15 20:04 ata-WDC_WD800JD-60JR_WD-WMAMD2644033 -> ../../sda
 lrwxrwxrwx 1 root root 10 May 15 20:04 ata-WDC_WD800JD-60JR_WD-WMAMD2644033-part1 -> ../../sda1
 lrwxrwxrwx 1 root root  9 May 15 20:04 edd-int13_dev80 -> ../../sda
 lrwxrwxrwx 1 root root 10 May 15 20:04 edd-int13_dev80-part1 -> ../../sda1
 lrwxrwxrwx 1 root root  9 May 15 20:04 edd-int13_dev81 -> ../../hda
 lrwxrwxrwx 1 root root 10 May 15 20:04 edd-int13_dev81-part1 -> ../../hda1
 lrwxrwxrwx 1 root root  9 May 15 20:04 scsi-SATA_WDC_WD800JD-60J_WD-WMAMD2644033 -> ../../sda
 llrwxrwxrwx 1 root root 10 May 15 20:04 scsi-SATA_WDC_WD800JD-60J_WD-WMAMD2644033-part8 -> ../../sda8

 unixspod@osslin5 :/> ls -l /dev/disk/by-path/
 lrwxrwxrwx 1 root root  9 May 15 20:04 pci-0000:00:1f.1-ide-0:0 -> ../../hda
 lrwxrwxrwx 1 root root 10 May 15 20:04 pci-0000:00:1f.1-ide-0:0-part1 -> ../../hda1
 lrwxrwxrwx 1 root root  9 May 15 20:04 pci-0000:00:1f.1-ide-1:0 -> ../../hdc
 lrwxrwxrwx 1 root root  9 May 15 20:04 pci-0000:00:1f.2-scsi-0:0:0:0 -> ../../sda
 lrwxrwxrwx 1 root root 10 May 15 20:04 pci-0000:00:1f.2-scsi-0:0:0:0-part1 -> ../../sda1

 unixspod@osslin5:/> ls -l /dev/disk/by-uuid/
 lrwxrwxrwx 1 root root 10 May 15 20:04 381d72cc-59f0-41ab-9c16-5166a938de92 -> ../../sda7
 lrwxrwxrwx 1 root root 10 May 15 20:04 3bd1f095-3943-4fa0-9813-b8c4fdb0c42e -> ../../sda8
 lrwxrwxrwx 1 root root 10 May 15 20:04 3c5d66a3-5476-4ab4-b01a-801f39b40b66 -> ../../hda1
 lrwxrwxrwx 1 root root 10 May 15 20:04 5d3c4512-fd6e-4e70-bad2-3faf3a25ca25 -> ../../sda6

Similiarly there are rules to tie a particular ethernet address to an interface name.

<extract from 30-net_persistent_names.rules>
 SUBSYSTEM=="net", ACTION=="add", SYSFS{address}=="00:12:79:de:f4:5d", IMPORT="/lib/udev/rename_netiface %k eth0"

!!! This should be born in mind when changing a network card !!!

udev informs applications of the new device through the Hardware Abstraction Layer ( HAL ).