The Linux Device Model
来源:
作者:
时间:2008-06-26
Tag:
点击:
Hotplug and Coldplug
Linux hotplug has recently changed considerably. Earlier, the kernel used to notify user space about hotplug events by invoking a helper program registered via the /proc filesystem. But when the latest 2.6 kernels detect hotplug, they dispatch uevents to user space via netlink sockets. Netlink sockets are an efficient mechanism to communicate between kernel space and user space via socket APIs. At the user space end, udevd receives the uevents and manages hotplug.
It’s interesting to see how hotplug handling has evolved recently. A Fedora Core 3 system running a udev-039 package and a 2.6.9 kernel has a symbolic link to a udev helper under the default hotplug directory, /etc/hotplug.d/default:
$ ls –l /etc/hotplug.d/default/
…
lrwcrwxrwx 1 root root 14 May 11 2005 10-udev.hotplug -> /sbin/udevsend
…
When the kernel detects a hotplug event, it invokes a user space helper registered with /proc/sys/kernel/hotplug, which defaults to /sbin/hotplug. /sbin/hotplug receives the attributes of the hotplugged device in its environment. It runs /etc/hotplug.d/default/10-udev.hotplug after executing other scripts under /etc/hotplug/. When /sbin/udevsend thus gets executed, it passes on the hotplugged device information to udevd, which manages subsequent node creation and removal.
On a Fedora Core 4 system running udev-058 and a 2.6.11 kernel, the story changes somewhat. udevsend itself replaces /sbin/hotplug:
$ cat /proc/sys/kernel/hotplug
/sbin/udevsend
On a Fedora Core 5 machine running udev-084 and a 2.6.15 kernel, udevd assumes full responsibility of managing hotplug without depending on udevsend. Udevd now pulls hotplug events directly from the kernel via netlink sockets (see Figure One). /proc/sys/kernel/hotplug is now empty:
$ cat /proc/sys/kernel/hotplug
$
Udev also handles coldplug. Device that are connected prior to system boot are said to be “coldplugged.” Since udev is part of user space and is started only after the kernel boots, a special mechanism is needed to support coldplug. The kernel creates a uevent file under sysfs for all devices and emits coldplug events to those files. When udev starts, it reads all the uevent files from /sys and emulates hotplug over the coldplugged devices.
Microcode Downloads
You have to feed microcode to some devices before they can get ready for action. A common mechanism used by drivers to access microcode was to store them in static arrays inside header files. But microcode is usually distributed as proprietary binary images by device vendors and doesn’t mix homogeneously with the GPL kernel. The solution apparently is to separately maintain microcode in user space and pass them down to the kernel when required. Sysfs and udev provide an infrastructure to achieve this.
Let’s take the example of the Intel PRO/Wireless 2100 Wifi adapter to walk through the new steps for downloading microcode:
1.Download the required firmware images from http://ipw2100.sourceforge.net/firmware.php and save them in /lib/firmware on your system.
2.Insert the driver module (modprobe ipw2100). The module initialization routine invokes request_firmware(”ipw2100-1.3.fw”).
3.This creates a sysfs directory called /sys/class/firmware/your-device/ and dispatches a hotplug uevent to user space along with the identity of the requested firmware image.
4.Udevd receives this hotplug event and responds by invoking /sbin/firmware_helper. You need a line similar to ACTION==”add”, SUBSYSTEM==”firmware”, RUN=”/sbin/firmware_helper” in a rule file under /etc/udev/rules.d.
5./sbin/firmware_helper looks inside /lib/firmware/ to locate the requested firmware image, ipw2100-1.3.fw. It dumps the image to /sys/class/0000:02:02.0/data (0000:02:02:0 is the PCI bus/device/function identifier of the Wifi adapter in this case).
6.The driver downloads the received microcode onto the device and calls release_firmware() to free the corresponding data structures. The corresponding directory under /sys/class/firmware is also erased.
7.The driver goes through the rest of the initializations and the Wifi adapter beacons.
Module Auto-Loading
Automatically loading kernel modules on demand is a convenient feature supported on Linux. To understand how the kernel emits a “module fault” and how udev handles it, let’s insert a Xircom CardBus Ethernet adapter into a laptop:
1.During compile time, device support information is generated in the driver module object. The driver declares the identity of the devices that it knows about. Take a peek at the driver that supports the Xircom CardBus Ethernet combo card (drivers/net/tulip/xircom_cb.c) and find this snippet:
static struct pci_device_id xircom_pci_table[] =
{
{0×115D, 0×0003, PCI_ANY_ID, PCI_ANY_ID,},
{0,},
};
MODULE_DEVICE_TABLE(pci, xircom_pci_table);
This declares that the driver can support any card having a PCI vendor ID of 0×115D and a PCI device ID of 0×0003. When you install the driver module, the depmod utility looks inside the module image and deciphers the IDs present in the device table. It then adds the following entry to /lib/modules/kernel-version/modules.alias (v stands for VendorID, d for DeviceID, sv for subvendorID, and * for wildcard match):
alias pci:v0000115Dd00000003sv*sd*bc*sc*i* xircom_cb
2.When you hotplug the Xircom card into a CardBus slot, the kernel generates a uevent that announces the identity of the newly added device. You can look at the generated events using udevmonitor:
$ udevmonitor ––env
…
MODALIAS=pci:v0000115Dd00000003sv0000115Dsd00001181bc02sc00i00
…
3.Udevd receives the uevents via netlink sockets. It invokes modprobe with the MODALIAS information that the kernel passed up to it:
modprobe pci:v0000115Dd00000003sv0000115Dsd00001181bc02sc00i00
4.modprobe searches for a match in /lib/modules/kernel-version/modules.alias and proceeds to insert xircom_cb:
$ lsmod
Module Size Used by
xircom_cb 10433 0
…
The card is now ready to surf.
Looking at the Sources
The kobject implementation and related programming interfaces live in lib/kobject.c and include/linux/kobject.h. Look at drivers/base/sys.c for the sysfs implementation. The device class APIs can be found in drivers/base/class.c. Dispatching hotplug uevents via netlink sockets is accomplished in lib/kobject_uevent.c). Udev sources and documentation can be downloaded from http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html.
Sreekrishnan Venkateswaran has been working for IBM India for over ten years. His recent projects include porting Linux to a pacemaker programmer and writing firmware for a lung biopsy device. You can reach Krishnan at
class="emailaddress"krishhna@gmail.com.
