Writing Device Drivers

Chapter 1 SunOS Kernel and Device Tree

This chapter provides an overview of the SunOS kernel and the manner in which it represents devices as nodes in a device tree. It covers general kernel structure and function, and the Solaris 7 Device Driver Interface/Driver Kernel Interface (DDI/DKI). In addition, driver binding to device nodes is discussed in relation to both specific and generic device names.

What Is the Kernel?

The SunOS kernel is a program that manages system resources. It insulates applications from the system hardware and provides them with essential system services such as input/output (I/O) management, virtual memory, and scheduling. The kernel consists of object modules that are dynamically loaded into memory when needed.

The kernel provides a set of interfaces for applications to use called system calls. System calls are documented in the Solaris 2.7 Reference Manual (see Intro(2)). The function of some system calls is to invoke a device driver to perform I/O. Device drivers are loadable modules that insulate the kernel from device hardware and manage data transfers.

The remainder of this book discusses the specifics of device drivers. For details on compiling and installing a device driver, see Chapter 15, Loading and Unloading Drivers. The following sections provide additional high-level information on the SunOS operating system.

Multithreading Considerations

In most UNIX systems, the process is the unit of execution. In the SunOS 5.7 system, a thread is the unit of execution. A thread is a sequence of instructions executed within a program. A process consists of one or more threads. There are two types of threads: application threads, which run in user space, and kernel threads, which run in kernel space.

The kernel is multithreaded (MT). Many kernel threads can be running kernel code, and may be doing so concurrently on a multiprocessor (MP) machine. Kernel threads may also be pre-empted by other kernel threads at any time. This is a departure from the traditional UNIX model where only one process can run kernel code at any one time, and that process is not pre-emptable (though it is interruptible).

The multithreading of the kernel imposes some additional restrictions on the device drivers. For more information on multithreading considerations, see Chapter 4, Multithreadingand Appendix G, Advanced Topics.

Virtual Memory

A complete overview of the SunOS virtual memory (VM) system is beyond the scope of this book, but two virtual memory terms of special importance are used when discussing device drivers: virtual address and address space.

Special Files

In UNIX, devices are treated as files. They are represented in the file system by special files. These files are advertised by the device driver and commonly reside in the /devices directory hierarchy.

Special files may be of type block or character. The type indicates which kind of device driver operates the device.

Associated with each special file is a device number. This consists of a major number and a minor number. The major number identifies the device driver associated with the special file. The minor number is created and used by the device driver to further identify the special file. Usually, the minor number is an encoding that identifies the device the driver should access and the type of access to perform. The minor number, for example, could identify a tape device requiring backup and also specify whether the tape needs to be rewound when the backup operation is complete.

Dynamic Loading of Kernel Modules

Kernel modules are loaded dynamically as references are made to them. For example, when a device special file is opened (see open(2)), the corresponding driver is loaded if it is not already in memory. Device drivers must provide support for dynamic loading. See Chapter 5, Autoconfiguration, for more details about the loadable module interface.

Overview of the Solaris 7 DDI/DKI

In System V Release 4 (SVR4), the interface between device drivers and the rest of the UNIX kernel has been standardized and documented in Section 9 of the of the Solaris 2.7 Reference Manual. The reference manual documents driver entry points, driver-callable functions and kernel data structures used by device drivers. These interfaces, known collectively as the Solaris 7 Device Driver Interface/Driver Kernel Interface (Solaris 7 DDI/DKI), are divided into the following subdivisions:

The Solaris 7 DDI/DKI, like its SVR4 counterpart, is intended to standardize and document all interfaces between device drivers and the kernel. In addition, the Solaris 7 DDI/DKI is designed to allow source compatibility for drivers on any SunOS 5.7-based machine, regardless of the processor architecture (such as SPARC or x86). It is also intended to provide binary compatibility for drivers running on any SunOS 5.7-based processor, regardless of the specific platform architecture (sun4c, sun4d, sun4m, sun4u, i86pc). Drivers using only kernel facilities that are part of the Solaris 7 DDI/DKI are known as Solaris 7 DDI/DKI-compliant device drivers.

The Solaris 7 DDI/DKI allows platform-independent device drivers to be written for SunOS 5.7-based machines. These shrink-wrapped (binary compatible) drivers allow third-party hardware and software to be more easily integrated into SunOS 5.7-based machines. The Solaris 7 DDI/DKI is designed to be architecture independent and enable the same driver to work across a diverse set of machine architectures.

Platform independence is accomplished in the design of DDI portions of the Solaris 7 DDI/DKI. The following main areas are addressed:

Device Tree

The kernel uses a tree structure to represent various physical machine configurations. Each node in the tree structure is described by a device-information structure. Standard device drivers and their devices are associated with leaf nodes. These drivers are called leaf drivers. Bus drivers are associated with bus nexus nodes and are called bus nexus drivers. This manual documents writing leaf drivers and one type of nexus driver, a SCSI host bus adapter (HBA) driver. This manual does not document any other type of bus nexus driver. Figure 1-1 illustrates two possible device tree configurations.

Figure 1-1 Possible Device Tree Configurations

Graphic

The topmost node in the device tree is called the root node. The tree structure creates a parent-child relationship between nodes. This parent-child relationship is the key to architectural independence. When a leaf or bus nexus driver requires a service that is architecturally dependent in nature, it requests its parent to provide the service.

The intermediate nodes in the tree are generally associated with buses, such as the SBus, SCSI, and PCI buses. These nodes are called bus nexus nodes and the drivers associated with them are called bus nexus drivers. Bus nexus drivers encapsulate the architectural dependencies associated with a particular bus.

This approach enables drivers to function regardless of the architecture of the machine or the processor. The xyz driver, for example, is source compatible with the architectural configurations shown in Figure 1-1; it can be binary compatible if the system uses the same instruction set architecture.

Additionally, in Figure 1-1, the bus nexus driver associated with the PCI-to-SBus adapter card handles all of the architectural dependencies of the interface. The xyz driver only needs to determine that it is connected to an SBus.

Example Device Tree

In this example, the system builds a tree structure that contains information about the devices connected to the machine at boot time. The system uses this information to create a dependency tree with bus nexus nodes and leaf nodes.

Figure 1-2 illustrates a sample device tree for a frame buffer (SUNW,ffb), a pseudo bus nexus node, and several PCI devices associated with a PCI bus nexus node.

Figure 1-2 Example Device Tree

Graphic

In Figure 1-2, the SUNW,ffb leaf node represents a system frame buffer. The pseudo bus nexus node is the parent node of any pseudo device drivers (drivers without hardware). The PCI bus nexus node is the parent node for the following children:

Device Drivers

Associated with each leaf or bus nexus node may be a device driver. Each driver has associated with it a device operations structure (see dev_ops(9S)) that defines the operations that the device driver can perform. The device operations structure contains function pointers for generic operations such as getinfo(9E) and attach(9E). It also contains a pointer to operations specific to bus nexus drivers and a pointer to operations specific to leaf drivers.

Displaying the Device Tree

The device tree can be displayed in two ways:

  1. The prtconf(1M) command displays all of the device nodes in the device tree.

  2. The /devices hierarchy is a representation of the device tree; use ls(1) to view it.


    Note -

    /devices displays only devices that have drivers configured into the system. prtconf(1M) shows all device nodes regardless of whether a driver for the device exists on the system or not.


prtconf(1M)

The prtconf(1M) command (excerpted example follows) displays all the devices in the system:

SUNW,Ultra-1
 ...
	pci, instance #0
								ebus, instance #0
       auxio (driver not attached)
       power (driver not attached)
       SUNW,pll (driver not attached)
       sc (driver not attached)
       se, instance #0
       su, instance #0
       su, instance #1
       ecpp (driver not attached)
       fdthree (driver not attached)
       eeprom (driver not attached)
       flashprom (driver not attached)
       SUNW,CS4231 (driver not attached)
 								network, instance #0
 								scsi, instance #0
       disk (driver not attached)
       tape (driver not attached)
       sd, instance #0
       sd, instance #1 (driver not attached)
       sd, instance #2 (driver not attached)
       sd, instance #3 (driver not attached)
       sd, instance #4 (driver not attached)
       sd, instance #5 (driver not attached)
       ....
pci, instance #1
SUNW,UltraSPARC-II (driver not attached)
SUNW,ffb (driver not attached)
pseudo, instance #0 

/devices

The /devices hierarchy provides a name space that represents the device tree. Following is an abbreviated listing of the /devices name space. The sample output corresponds to the example device tree and prtconf(1M) output shown previously.

/devices
/devices/pseudo
/devices/SUNW,ffb@1e,0:ffb0
/devices/pci@1f,4000/ebus@1
/devices/pci@1f,4000/scsi@3
/devices/pci@1f,4000/scsi@3:devctl
/devices/pci@1f,4000/ebus@1/ecpp@14,3043bc:ecpp0
/devices/pci@1f,4000/ebus@1/se@14,400000:0,hdlc
/devices/pci@1f,4000/ebus@1/se@14,400000:1,hdlc
/devices/pci@1f,4000/ebus@1/se@14,400000:a
/devices/pci@1f,4000/ebus@1/se@14,400000:a,cu
/devices/pci@1f,4000/ebus@1/se@14,400000:b
/devices/pci@1f,4000/ebus@1/se@14,400000:b,cu
/devices/pci@1f,4000/ebus@1/SUNW,CS4231@14,200000:sound,audio
/devices/pci@1f,4000/ebus@1/SUNW,CS4231@14,200000:sound,audioctl
/devices/pci@1f,4000/scsi@3/sd@0,0:a
/devices/pci@1f,4000/scsi@3/sd@0,0:a,raw 

Binding a Driver to a Device Node

In addition to constructing the device tree, the kernel must also determine the drivers that will be used to manage the devices.

Binding a driver to a device node refers to the process by which the system selects a driver to manage a particular device. The driver binding name is the name that links a driver to a unique device node in the device information tree. For each device in the device tree, the system chooses a driver from a list of drivers.

Each device node has a name property associated with it. This property may be derived either from an external agent such as the PROM during system boot or from a driver.conf file. In either case, the name property represents the node name assigned to a device in the device tree.

Figure 1-3 Device Node Names

Graphic

A device node may also have a compatible property associated with it. The compatible property (if it exists) contains an ordered list of one or more possible driver names for the device.

The system uses both the name and the compatible properties to select a driver for the device. If the compatible property exists, the system first attempts to match the contents of the compatible property to a driver on the system. The compatible property is simply a list of possible driver names from which the system can determine the specific driver binding name for the device.

Beginning with the first driver name on the compatible property list, the system attempts to match the driver name to a known driver on the system. It processes each entry on the list until either a match is found or the end of the list is reached.

If the contents of either the name property or the compatible property match a driver on the system, then that driver is bound to the device node. If no match is found, no driver is bound to the device node.

Generic Device Names

Some devices with a compatible property use a generic device name as the value for the name property. Generic device names describe the function of a device without actually identifying a specific driver for the device. For example, a SCSI host bus adapter may have a generic device name of scsi. An Ethernet device may have a generic device name of ethernet.

The compatible property allows the system to determine alternate driver names (like glm for scsi HBA device drivers or hme for ethernet device drivers) for devices with a generic device name.

Devices with generic device names must supply a compatible property.


Note -

For a complete description of generic device names, see the IEEE 1275 Open Firmware Boot Standard.


Figure 1-4 and Figure 1-5 show two device nodes: one node uses a specific device name and the other uses a generic device name.

For the device node with a specific device name, the driver binding name SUNW,ffb is the same name as the device node name.

Figure 1-4 Specific Driver Node Binding

Graphic

For the device node with the generic device name display, the driver binding name SUNW,ffb is the first name on the compatible property driver list that matches a driver on the system driver list. In this case, display is a generic device name for frame buffers.

Figure 1-5 Generic Driver Node Binding

Graphic