
\subsection*{Abstract} 


A new device driver model has been designed and developed for the 2.5
version of the Linux Kernel. The original intent of this model was to
provide a means to generically represent and operate on every device
in a computer. This would allow modern power management routines to
perform properly ordered suspend and resume operations on the entire
device space during system power state transitions. 

During the integration of the initial model, it became apparent that
many more concepts related to devices besides power management
information could be generalized and shared. The new driver model has
evolved to provide generic representations of several objects,
including:

\begin{itemize}
\begin{footnotesize}
\item Devices
\item Device drivers 
\item Bus drivers 
\item Device Classes 
\item Device Interfaces 
\end{footnotesize}
\end{itemize}

 The model also provides a set of functions to operate on each of
those objects. This has provided the opportunity to consolidate and
simplify a large quantity of kernel code and data structures. 

The new driver model has been included in the mainstream kernel, since
version 2.5.1, and continues to mature and evolve as more drivers are
converted to exploit its infrastructure. 

This document describes the design and implementation of the new
driver model. It covers the description of the objects and their
programming interfaces, as well as their conceptual and programmatic
interactions with one another. It also includes appendices on the
kobject infrastructure and the sysfs filesystem. These are two
important features that were developed as a result of the driver
model, yet were divorced from the model because of their more general
purpose. They are covered in this document in the context of how they
are used in the driver model.  

\section{Introduction}

\subsection*{Theory}
	
The driver model was created by analyzing the behavior of the PCI and
USB bus drivers. These buses are ubiquitous in contemporary computer
systems, and represent the majority of the devices that the kernel
supports. They contain the most mature support for dynamic addition,
removal, and power management of devices and drivers. These features
had already been permeating other kernel bus drivers, with inspiration
from the PCI and USB subsystems. They were considered appropriate
bases of assumptions, and are described below. 

These assumptions hold true for the majority of instances of objects
represented by the driver model. The minority of objects are
considered exceptions, and must work around the driver model
assumptions. 


A bus driver is a set of code that communicates with a peripheral bus
of a certain type. Some examples of bus drivers in the kernel
include:

\begin{itemize}
\begin{footnotesize}
\item PCI
\item USB
\item SCSI
\item IDE
\item PCMCIA
\end{footnotesize}
\end{itemize}

Bus drivers maintain a list of devices that are present on all
instances of that bus type, and a list of registered drivers. A bus
driver is compile-time option, and may usually be compiled as a
module. There will never be multiple instances of a driver for the
same bus type at the same time. Most, if not all, of its internal data
structures are statically allocated.

A bus instance represents the presence of a bus of a particular type,
such as PCI Bus 0. They are dynamically allocated when the bus
instance is discovered. They contain a list of devices, as well as
data describing the connection to the device. Bus instances are not
currently represented in the driver model. However, they are mentioned
here to note the distinction between them and bus driver objects. 

During startup, a bus driver discovers instances of its bus type. It
scans the bus for present devices and allocates data structures to
describe each device. Most of this information is bus-specific, such
as the bus address of the device and device identification
information. The bus driver need not know of the function the device
performs. This object is inserted into the bus's list of devices, and
the bus driver attempts to bind it to a device driver.

A device class describes a function that a device performs, regardless
of the bus on which a particular device resides. Examples of device
classes are:

\begin{itemize}
\begin{footnotesize}
\item Audio output devices
\item Network devices
\item Disks
\item Input devices
\end{footnotesize}
\end{itemize}

A device class driver maintains lists of device and drivers that
belong to that class. They are optional bodies of code that may be
compiled as a module. Its data structures are statically allocated. A
device class defines object types to describe the devices registered
wit h it. These objects define the devices in the context of the class
only, since classes are independent of a device's bus type.

A device class is characterized by a set of interfaces that allow user
processes to communicate with devices of their type. An interface
defines a protocol for communicating with those devices, which is
characterized in a user space device node. A class may contain
multiple interfaces for communicating with devices, though the devices
and drivers of that class may not support all the interfaces of the
class.

A device driver is a body of code that implements one or more
interfaces of a device class for a set of devices on a specific bus
type. They contain some statically allocated structures to describe
the driver to its bus and class, and to maintain a list of bound
devices. 

During startup, a driver registers with its bus, and the bus inserts
the driver into its internal list of drivers. The bus then attempts to
bind the driver to the bus's list of devices. A bus compares a list of
bus-specific device ID numbers that it supports with the ID numbers of
the devices on the bus. If a match is made, the device is 'attached'
to the driver. The driver allocates a driver-specific object to
describe the device. This usually includes a class-specific object as
well, which the driver uses to register the device with it's class. 


\subsection*{Infrastructure}

The driver model provides a set of objects to represent the entities
described above. Previously, the kernel representations of these
objects, especially devices, have varied greatly based on the
functionality that they provide and the bus type for which they are
designed. Much of this information is specific to the type of object,
though some can be generically encoded, which are what compose the
driver model objects. 

Most of the members of driver model objects contian meta data
describing the object, and linkage information to represent membership
in groups and lists of subordinate objects. The driver model object
definitions can be found in the header file include/linux/device.h.

The driver model also provides a set of functions to operate on each
object. These functions are referred to the 'driver model core'
through this document. They are implemented in drivers/base/ in the
kernel source tree. Each set of operations is object-specific and
described in detail with the objects in their respective
sections. However, there are some commonalities between objects that
are reflected in the functions of the core. These are described here
to provide perspective on the model, and to avoid repeating the
purposes in each section.


Every driver model object supports dynamic addition and removal. Each
object has register() and unregister() functions specific to that
object. Registration initializes the object, inserts it into a list
of similar objects, and creates a  directory for the object in the
sysfs filesystem. Registration occurs when a device is discovered or a
module containing a device, bus, or class driver is inserted. 
Unregistration occurs when a driver's module is unloaded or a device
is physically removed. Unregistration removes the object's sysfs
directory and deletes it from the list of similar objects. 

To support dynamic removal, each object contains a reference
count that can be adjusted by object-specific get() and put()
functions. The get() routine should be called for an object before it
is used in a function. get() returns a reference to the object. The
put() routine should be called after a function is done using an
object. It has no return value. 

If, and only if, an object's reference count reaches 0 may the object
be freed, or its module be unloaded. Another process may still hold a
reference to the object when the object's unregister() function
returns. Blindly freeing an object's memory could cause the other
process to access invalid or reallocated memory. The method that the
driver model uses to prevent these bugs is described in the individual
objects' sections. 


The similarities of driver model objects, and the amount of replicated
code to perform similar operations on the objects prompted the effort
to create a generic object type to be shared across not only driver
model objects, but also across all complex kernel objects that
supported dynamic registration and reference counting. 

A kobject generically describes an object. It may be embedded in
larger data types to provide generic object meta data and a reference
counting mechanism. A subsystem represents a set of kobjects. A
kobject can be dynamically registered and unregistered with their
subsystem. When a kobject is registered, it is initialized and
inserted into its subsystem's list of objects. A directory in sysfs,
described below, is also created. Unregistration removes the
sysfs directory for the kobject and deletes it from its subsystem's
list. Kobjects also have a reference count and get() and put()
operations to adjust it. A kobject may belong to only one subsystem,
and a subsystem must contain only identically embedded kobjects.

The kobject functionality is very similar to the driver model
core. The driver model functions have been adapted to use the kobject
infrastructure, and some provide no more functionality than calling
the associated kobject function.  

The kobject and subsystem infrastructure is described in Appendix A.

The sysfs filesystem was originally created as a means to export
driver model objects and their attributes to user space. It has since
been integrated with the kobject infrastructure, so it can communicate
directly with the generic object, allowing it to do reference counting
on represented objects.  

All registered kobjects receive a directory in sysfs in a specific
location based on the kobject's ancestry. This provides user space
with a meaningful object hierarchy in the filesystem which can be
navigated through using basic file system tools, like ls(1), find(1),
and grep(1). 

Attributes of an object may be exported via sysfs, and are represented
as text files in the filesystem. Sysfs provides a means for user
processes to read and write attributes. The kernel exporters of
attributes may define methods called by sysfs when a read or write
operation is performed on an attribute file. 

The sysfs filesystem and its programming interface is discussed in Appendix B.



\subsection*{Summary}


The new driver model implements a large amount of infrastructure for
describing and operating on device-related objects. This
infrastructure has been able to eliminate redundant kernel code and
data structures, especially in the areas of object reference counting
and list membership management. This reduces the complexity of device,
bus and class drivers, making them easier to write and easier to
read. The consolidation of data structures also makes it easier to
implement common functions to operate on objects of traditionally
different objects. 

While this document describes the base objects and operations of the
driver model, there are many things it omits. It does not describe how
it is exploited for the purpose of power management or implementing a
dynamic and scalable device naming scheme. These topics are beyond the
scope of this document and reserved for other discussions.  

Similarly, this document only superficially describes the kobject
infrastructure and the sysfs filesystem. These are included only to
provide enough context to complete the discussion of the driver model,
and are best covered in other documents.
