
\section{Device Drivers}


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. Drivers are specific to both their class and bus. Only in rare
cases may drivers work on devices on two different bus types, and in
those cases, it is because of a abstraction layer internal to the
driver. Device drivers also contain a set of methods to perform
bus-specific operations for their target. The driver model defines
struct device\_driver to describe device drivers.

Device drivers are optional and may be loaded as modules. They
contain some statically allocated structures to describe the driver to
its bus and class, and to maintain a list of devices bound to
it. During startup, a driver registers an object with its bus. This
object contains basic description information, the 
bus-specific methods it implements, and a table of device IDs
supported by the driver. The bus driver inserts the driver into a list,
and attempts to bind the driver to devices present on the bus. When a
driver is bound to a device, it allocates a private structure, and
usually allocates the class-specific object for the
device. Traditionally, the device has registered the device with the
class manually, though the driver model is working to move that
functionality out of the drivers. 

A driver is detached from a device if the driver module is
unloaded. This involves unregistering the device from the class and
freeing the private structure it had allocated for the device.


\subsection*{Structural Overview}

struct device\_driver is designed to describe a device driver at a
simple level. It consists of data elements that are independent of bus
or class types, linkage information that is common to all buses and
classes, and a set of methods designed to be called from driver model
core code.

\begin{table}
\begin{footnotesize}
\begin{tabularx}{\linewidth}{|X|X|X|} \hline
\textit{Name}	& \textit{Return Type} & \textit{Description} \\ \hline \hline

name	& char *	& The name of the driver.
\\\hline

bus	& struct bus\_type	& The bus the driver belongs to.
\\\hline

devclass	& struct device\_class	& The class the driver belongs to.
\\\hline

unload\_sem	& struct semaphore	& Semaphore to protect against
	a driver module being unloaded while the driver is still
	referenced. 
\\\hline

kobj	& struct kobject	& Generic object information.
\\\hline

class\_list	& struct list\_head	& List entry in class's list
	of drivers. 
\\\hline

devices	& struct list\_head	& List of devices bound to driver.
\\\hline

\end{tabularx} \\
\end{footnotesize}
\caption{\footnotesize{struct device\_driver Data Fields.}}
\end{table}


Currently, the generic driver structure is intended to be embedded in
the bus-specific driver structures that already exist today. The bus
driver is then modified to forward the registration call to the
driver model core when the driver registers with its bus. This allows
a gradual transition phase while the individual drivers are modified
to use the generic fields. 

To smooth this transition, the bus drivers also supply parameters for
the generic structure on behalf of the bus-specific structures. This
is true for the methods of struct device\_driver. Many bus-specific
driver objects have methods similar to those in the generic driver
structure. A bus driver may implement methods for the generic
structure that simply forward method calls to methods in the
bus-specific structure. Drivers can become part of the driver model
without having to modify every driver structure. 

The bus drivers may also set the bus type for the driver, since it
receives the intermediate call. However, the driver should specify its
device class, since the class has no way of determining that. 

The 'kobj' member contains generic object meta data. This
object belongs to the driver subsystem of the driver's bus type. It 
is registered with the subsystem when the driver registers with
the driver model core. The 'class\_list' field is a list entry that
allows the drive to be inserted in its class's list of drivers. The
'devices' list is a list of devices that have been attached to the
driver. 

The 'unload\_sem' member is used by the core to prevent a driver
module from being unloaded while its reference count it still
positive. This semaphore is initialized to a locked state, and only
unlocked when a driver's reference count reaches 0. A driver may be
unregistered at any time, even if the reference count is 
positive. Unfortunately, after a driver is unloaded, its module is
removed unconditionally. If unregistering the driver did not remove
the last reference, the process blocks waiting for the reference count
to reach 0, and the semaphore to be released.

\begin{table}
\begin{footnotesize}
\begin{tabularx}{\linewidth}{|X|X|X|} \hline
\textit{Name}	& \textit{Return Type} & \textit{Description} \\ \hline \hline

probe (
  struct device * dev
)
& int
& Called to verify driver can be bound to device, and attach to
	device.
\\\hline

remove(
  struct device * dev
)
& int
& Called to detach driver from device.
\\\hline

shutdown(
  struct device * dev
)
& void
& Called during system shutdown sequence to quiesce devices.
\\\hline

suspend(
  struct device * dev,
  u32 state, 
  u32 level
)
& int
& Called during system suspend transition to put device to sleep.
\\\hline

resume(
  struct device * dev,
  u32 level
)
& int
& Called during system resume transition to wake device back up.
\\\hline

\end{tabularx} \\
\end{footnotesize}
\caption{\footnotesize{struct device\_driver Methods.}}
\end{table}


The methods of struct device\_driver are operations that the driver
model core calls when it needs to perform device-specific actions
during an otherwise generic operation. As before, the bus
may implement these methods for all registered drivers, and
simply forward the calls to the bus-specific driver methods.

'probe' is called to determine whether a device can support a specific
device. This is called during the driver binding operation, after the
bus has verified that the device's ID matches a supported ID. This
method is for the driver to verify that the hardware is in good,
working condition and it can be successfully initialized.  

This method is traditionally used to initialize the device and
register it with the driver's class. Discussion has surfaced several
times about separating the 'probe' method into 'probe' and 'start' (or
similar). 'probe' would only verify that the hardware was operational,
while 'add' would handle initialization and registration of the
device. Some common registration functionality could also be moved out
of the drivers and into the core, since it typically happens after
operational verification and before hardware initialization. For now,
'probe' remains dual-purposed and monolithic. 

'remove' is used to disengage the device from the driver. The driver
should shut down the device. 'remove' is called during the driver
unbinding operation, when either a device or a driver has been removed
from the system.  

'shutdown' is called during a reboot or shutdown cycle. It is intended to
quiesce the device during a shut down or reboot transition. It is
called only from device\_shutdown(), during a system reboot or
shutdown sequence.

'suspend' and 'resume' are called during system-wide and
device-specific power state transitions, though only it is currently
only used in the former. Power management is discussed in its own
section, and should be consulted for the details of the parameters of
these functions.



\subsection*{Programming Interface}

Device drivers have a programming interface similar to the other
driver model objects. They have register and unregister functions, as
well as routines to adjust the reference count. The only behavioral
difference is usage of the driver's 'unload\_sem' field, as described
above. 


\begin{table}
\begin{footnotesize}
\begin{tabularx}{\linewidth}{|X|X|X|} \hline
\textit{Name}	& \textit{Return Type} & \textit{Description} \\ \hline \hline

driver\_register(
  struct device\_driver *
)
& int
& Register driver with core.
\\\hline

driver\_unregister(
  struct device\_driver *
)
& void
& Unregister driver from core.
\\\hline

get\_driver(
  struct device\_driver *
)
& struct device *
& Increment driver's reference count.
\\\hline

put\_driver(
  struct device\_driver *
)
& void
& Decrement driver's reference count.
\\\hline

\end{tabularx} \\
\end{footnotesize}
\caption{\footnotesize{struct device\_driver Programming Interface.}}
\end{table}

