JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Writing Device Drivers
search filter icon
search icon

Document Information

Preface

Part I Designing Device Drivers for the Solaris Platform

1.  Overview of Solaris Device Drivers

Device Driver Basics

What Is a Device Driver?

What Is a Device Driver Entry Point?

Device Driver Entry Points

Entry Points Common to All Drivers

Device Access Entry Points

Loadable Module Entry Points

Autoconfiguration Entry Points

Kernel Statistics Entry Points

Power Management Entry Point

Summary of Common Entry Points

Entry Points for Block Device Drivers

Entry Points for Character Device Drivers

Entry Points for STREAMS Device Drivers

Entry Points for Memory Mapped Devices

Entry Points for Network Device Drivers

Entry Points for SCSI HBA Drivers

Entry Points for PC Card Drivers

Considerations in Device Driver Design

DDI/DKI Facilities

Device IDs

Device Properties

Interrupt Handling

Callback Functions

Software State Management

Programmed I/O Device Access

Direct Memory Access (DMA)

Layered Driver Interfaces

Driver Context

Returning Errors

Dynamic Memory Allocation

Hotplugging

2.  Solaris Kernel and Device Tree

3.  Multithreading

4.  Properties

5.  Managing Events and Queueing Tasks

6.  Driver Autoconfiguration

7.  Device Access: Programmed I/O

8.  Interrupt Handlers

9.  Direct Memory Access (DMA)

10.  Mapping Device and Kernel Memory

11.  Device Context Management

12.  Power Management

13.  Hardening Solaris Drivers

14.  Layered Driver Interface (LDI)

Part II Designing Specific Kinds of Device Drivers

15.  Drivers for Character Devices

16.  Drivers for Block Devices

17.  SCSI Target Drivers

18.  SCSI Host Bus Adapter Drivers

19.  Drivers for Network Devices

20.  USB Drivers

Part III Building a Device Driver

21.  Compiling, Loading, Packaging, and Testing Drivers

22.  Debugging, Testing, and Tuning Device Drivers

23.  Recommended Coding Practices

Part IV Appendixes

A.  Hardware Overview

B.  Summary of Solaris DDI/DKI Services

C.  Making a Device Driver 64-Bit Ready

D.  Console Frame Buffer Drivers

Index

Considerations in Device Driver Design

A device driver must be compatible with the Solaris OS, both as a consumer and provider of services. This section discusses the following issues, which should be considered in device driver design:

DDI/DKI Facilities

The Solaris DDI/DKI interfaces are provided for driver portability. With DDI/DKI, developers can write driver code in a standard fashion without having to worry about hardware or platform differences. This section describes aspects of the DDI/DKI interfaces.

Device IDs

The DDI interfaces enable drivers to provide a persistent, unique identifier for a device. The device ID can be used to identify or locate a device. The ID is independent of the device's name or number (dev_t). Applications can use the functions defined in libdevid(3LIB) to read and manipulate the device IDs registered by the drivers.

Device Properties

The attributes of a device or device driver are specified by properties. A property is a name-value pair. The name is a string that identifies the property with an associated value. Properties can be defined by the FCode of a self-identifying device, by a hardware configuration file (see the driver.conf(4) man page), or by the driver itself using the ddi_prop_update(9F) family of routines.

Interrupt Handling

The DDI/DKI addresses the following aspects of device interrupt handling:

Device interrupt sources are contained in a property called interrupt, which is either provided by the PROM of a self-identifying device, in a hardware configuration file, or by the booting system on the x86 platform.

Callback Functions

Certain DDI mechanisms provide a callback mechanism. DDI functions provide a mechanism for scheduling a callback when a condition is met. Callback functions can be used for the following typical conditions:

Callback functions are somewhat similar to entry points, for example, interrupt handlers. DDI functions that allow callbacks expect the callback function to perform certain tasks. In the case of DMA routines, a callback function must return a value indicating whether the callback function needs to be rescheduled in case of a failure.

Callback functions execute as a separate interrupt thread. Callbacks must handle all the usual multithreading issues.


Note - A driver must cancel all scheduled callback functions before detaching a device.


Software State Management

To assist device driver writers in allocating state structures, the DDI/DKI provides a set of memory management routines called the software state management routines, also known as the soft-state routines. These routines dynamically allocate, retrieve, and destroy memory items of a specified size, and hide the details of list management. An instance number is used to identify the desired memory item. This number is typically the instance number assigned by the system.

Routines are provided for the following tasks:

See Loadable Driver Interfaces for an example of how to use these routines.

Programmed I/O Device Access

Programmed I/O device access is the act of reading and writing of device registers or device memory by the host CPU. The Solaris DDI provides interfaces for mapping a device's registers or memory by the kernel as well as interfaces for reading and writing to device memory from the driver. These interfaces enable drivers to be developed that are platform and bus independent, by automatically managing any difference in device and host endianness as well as by enforcing any memory-store sequence requirements imposed by the device.

Direct Memory Access (DMA)

The Solaris platform defines a high-level, architecture-independent model for supporting DMA-capable devices. The Solaris DDI shields drivers from platform-specific details. This concept enables a common driver to run on multiple platforms and architectures.

Layered Driver Interfaces

The DDI/DKI provides a group of interfaces referred to as layered device interfaces (LDI). These interfaces enable a device to be accessed from within the Solaris kernel. This capability enables developers to write applications that observe kernel device usage. For example, both the prtconf(1M) and fuser(1M) commands use LDI to enable system administrators to track aspects of device usage. The LDI is covered in more detail in Chapter 14, Layered Driver Interface (LDI).

Driver Context

The driver context refers to the condition under which a driver is currently operating. The context limits the operations that a driver can perform. The driver context depends on the executing code that is invoked. Driver code executes in four contexts:

The manual pages in section 9F document the allowable contexts for each function. For example, in kernel context the driver must not call copyin(9F).

Returning Errors

Device drivers do not usually print messages, except for unexpected errors such as data corruption. Instead, the driver entry points should return error codes so that the application can determine how to handle the error. Use the cmn_err(9F) function to write messages to a system log that can then be displayed on the console.

The format string specifier interpreted by cmn_err(9F) is similar to the printf(3C) format string specifier, with the addition of the format %b, which prints bit fields. The first character of the format string can have a special meaning. Calls to cmn_err(9F) also specify the message level, which indicates the severity label to be printed. See the cmn_err(9F) man page for more details.

The level CE_PANIC has the side effect of crashing the system. This level should be used only if the system is in such an unstable state that to continue would cause more problems. The level can also be used to get a system core dump when debugging. CE_PANIC should not be used in production device drivers.

Dynamic Memory Allocation

Device drivers must be prepared to simultaneously handle all attached devices that the drivers claim to drive. The number of devices that the driver handles should not be limited. All per-device information must be dynamically allocated.

void *kmem_alloc(size_t size, int flag);

The standard kernel memory allocation routine is kmem_alloc(9F). kmem_alloc() is similar to the C library routine malloc(3C), with the addition of the flag argument. The flag argument can be either KM_SLEEP or KM_NOSLEEP, indicating whether the caller is willing to block if the requested size is not available. If KM_NOSLEEP is set and memory is not available, kmem_alloc(9F) returns NULL.

kmem_zalloc(9F) is similar to kmem_alloc(9F), but also clears the contents of the allocated memory.


Note - Kernel memory is a limited resource, not pageable, and competes with user applications and the rest of the kernel for physical memory. Drivers that allocate a large amount of kernel memory can cause system performance to degrade.


void kmem_free(void *cp, size_t size);

Memory allocated by kmem_alloc(9F) or by kmem_zalloc(9F) is returned to the system with kmem_free(9F). kmem_free() is similar to the C library routine free(3C), with the addition of the size argument. Drivers must keep track of the size of each allocated object in order to call kmem_free(9F) later.

Hotplugging

This manual does not highlight hotplugging information. If you follow the rules and suggestions for writing device drivers given in this book, your driver should be able to handle hotplugging. In particular, make sure that both autoconfiguration (see Chapter 6, Driver Autoconfiguration) and detach(9E) work correctly in your driver. In addition, if you are designing a driver that uses power management, you should follow the information given in Chapter 12, Power Management. SCSI HBA drivers might need to add a cb_ops structure to their dev_ops structure (see Chapter 18, SCSI Host Bus Adapter Drivers) to take advantage of hotplugging capabilities.

Previous versions of the Solaris OS required hotpluggable drivers to include a DT_HOTPLUG property, but this property is no longer required. Driver writers are free, however, to include and use the DT_HOTPLUG property as they see fit.