Reworking system devices
[Posted June 11, 2003 by corbet]
"System" devices, as seen by the Linux device model, are components wired
deeply into the core of the system, and which do not sit on a separate
bus. Such devices include the CPUs, interrupt controller, timer, etc.
They do not behave like most other devices (for example, you cannot open
and write to them), and they are usually a vital part of the system as a
whole. System devices are easily confused with "platform" devices - things
like serial and parallel ports which usually are found on the system
motherboard, but which act more like regular peripherals.
Up through 2.5.70, the Linux device model has treated system devices like
most other devices. There is a fake "system bus" to which system devices
"attach", and the usual driver methods are expected to be present. But, as
Patrick Mochel noted in his patch
reorganizing the system device API, "System devices are special, and
after two years of listening to Linus preach this, it finally sunk in
enough to do something about."
System devices are special in a number of ways. You generally know that
they have to be present (you don't have to go probing for them), and there
is little point in trying to load a driver for them. When dealing with
power transitions (suspending or resuming the system), system devices need
to be the last to shut down and the first to restart. They have weird
interfaces that no other devices have; consider, for example, controlling
CPU frequency policy. System devices, in other words, need to be treated
in their own, particular way.
So, as of 2.5.71, there is a new API and user-space interface for working
with system devices. There is a new include file
(<linux/sysdev.h>) which defines a class type for system
devices:
struct sysdev_class {
struct list_head drivers;
/* Default operations for these types of devices */
int (*shutdown)(struct sys_device *);
int (*save)(struct sys_device *, u32 state);
int (*suspend)(struct sys_device *, u32 state);
int (*resume)(struct sys_device *);
int (*restore)(struct sys_device *);
struct kset kset;
};
A new type of system device is set up by filling in one of those structures
and passing it to sysdev_class_register(). An actual system
device is then created by filling in one of:
struct sys_device {
u32 id;
struct sysdev_class * cls;
struct kobject kobj;
};
and passing it to sys_device_register(). The class-specific
suspend and resume functions will now be called at the right times for that
device, and a new sysfs directory will show up under
/sys/devices/system with a default set of attributes.
For more complicated sorts of devices, it is still possible to register one
or more "drivers" which add functionality. There is yet another structure
to fill in:
struct sysdev_driver {
struct list_head entry;
int (*add)(struct sys_device *);
int (*remove)(struct sys_device *);
int (*shutdown)(struct sys_device *);
int (*save)(struct sys_device *, u32 state);
int (*suspend)(struct sys_device *, u32 state);
int (*resume)(struct sys_device *);
int (*restore)(struct sys_device *);
};
A call to sysdev_driver_register() will associate this driver with
a specific system device class. Multiple drivers can be registered; each
will be given a chance to respond to events involving devices in the given
class. The add() and remove() methods allow the driver
to respond to the creation or destruction of system devices - generally by
adding or removing attributes to their sysfs entries. Thus, "drivers" in
this context take on the functions handled by "interfaces" elsewhere in the
driver model.
The new system device mechanism is thus a sort of hybrid combination of the
device, driver, bus, and class structures used by "regular" devices. The
new code is, perhaps, a step in the right direction, but it clearly
illustrates one thing: the Linux device model still has not stabilized, and
may not for a while yet. The device model is a major change to how things
are done in the kernel, and the developers are still feeling around for the
best way of doing things.
(
Log in to post comments)