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

Document Information


Part I Designing Device Drivers for the Solaris Platform

1.  Overview of Solaris Device Drivers

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

USB in the Solaris Environment

USBA 2.0 Framework

USB Client Drivers

Binding Client Drivers

How USB Devices Appear to the System

USB Devices and the Solaris Device Tree

Compatible Device Names

Devices With Multiple Interfaces

Checking Device Driver Bindings

Basic Device Access

Before the Client Driver Is Attached

The Descriptor Tree

Registering Drivers to Gain Device Access

Device Communication

USB Endpoints

The Default Pipe

Pipe States

Opening Pipes

Closing Pipes

Data Transfer

Synchronous and Asynchronous Transfers and Callbacks


Flushing Pipes

Device State Management

Hotplugging USB Devices

Hotplug Callbacks

Hot Insertion

Hot Removal

Hot Reinsertion

Power Management

Device Power Management

System Power Management


Utility Functions

Device Configuration Facilities

Getting Interface Numbers

Managing Entire Devices

Multiple-Configuration Devices

Modifying or Getting the Alternate Setting

Other Utility Functions

Retrieving a String Descriptor

Pipe Private Data Facility

Clearing a USB Condition

Getting Device, Interface, or Endpoint Status

Getting the Bus Address of a Device

Sample USB Device Driver

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


Basic Device Access

This section describes how to access a USB device and how to register a client driver. This section also discusses the descriptor tree.

Before the Client Driver Is Attached

The following events take place before the client driver is attached:

  1. The PROM (OBP/BIOS) and USBA framework gain access to the device before any client driver is attached.

  2. The hub driver probes devices on each of its hub's ports for identity and configuration.

  3. The default control pipe to each device is opened, and each device is probed for its device descriptor.

  4. Compatible names properties are constructed for each device, using the device and interface descriptors.

The compatible names properties define different parts of the device that can be individually bound to client drivers. Client drivers can bind either to the entire device or to just one interface. See Binding Client Drivers.

The Descriptor Tree

Parsing descriptors involves aligning structure members at natural boundaries and converting the structure members to the endianness of the host CPU. Parsed standard USB configuration descriptors, interface descriptors, and endpoint descriptors are available to the client driver in the form of a hierarchical tree for each configuration. Any raw class-specific or vendor-specific descriptor information also is available to the client driver in the same hierarchical tree.

Call the usb_get_dev_data(9F) function to retrieve the hierarchical descriptor tree. The “SEE ALSO” section of the usb_get_dev_data(9F) man page lists the man pages for each standard USB descriptor. Use the usb_parse_data(9F) function to parse raw descriptor information.

A descriptor tree for a device with two configurations might look like the tree shown in the following figure.

Figure 20-3 A Hierarchical USB Descriptor Tree

Diagram shows a tree of pairs of descriptors for each interface of a device with two configurations.

The dev_cfg array shown in the above figure contains nodes that correspond to configurations. Each node contains the following information:

The node that represents the second interface of the second indexed configuration is at dev_cfg[1].cfg_if[1] in the diagram. That node contains an array of nodes that represent the alternate settings for that interface. The hierarchy of USB descriptors propagates through the tree. ASCII strings from string descriptor data are attached where the USB specification says these strings exist.

The array of configurations is non-sparse and is indexed by the configuration index. The first valid configuration (configuration 1) is dev_cfg[0]. Interfaces and alternate settings have indices that align with their numbers. Endpoints of each alternate setting are indexed consecutively. The first endpoint of each alternate setting is at index 0.

This numbering scheme makes the tree easy to traverse. For example, the raw descriptor data of endpoint index 0, alternate 0, interface 1, configuration index 1 is at the node defined by the following path:


An alternative to using the descriptor tree directly is using the usb_lookup_ep_data(9F) function. The usb_lookup_ep_data(9F) function takes as arguments the interface, alternate, which endpoint, endpoint type, and direction. You can use the usb_lookup_ep_data(9F) function to traverse the descriptor tree to get a particular endpoint. See the usb_get_dev_data(9F) man page for more information.

Registering Drivers to Gain Device Access

Two of the first calls into the USBA 2.0 framework by a client driver are calls to the usb_client_attach(9F) function and the usb_get_dev_data(9F) function. These two calls come from the client driver's attach(9E) entry point. You must call the usb_client_attach(9F) function before you call the usb_get_dev_data(9F) function.

The usb_client_attach(9F) function registers a client driver with the USBA 2.0 framework. The usb_client_attach(9F) function enforces versioning. All client driver source files must start with the following lines:

#define USBDRV_MAJOR_VER        2
#define USBDRV_MINOR_VER        minor-version
#include <sys/usb/usba.h>

The value of minor-version must be less than or equal to USBA_MINOR_VER. The symbol USBA_MINOR_VER is defined in the <sys/usb/usbai.h> header file. The <sys/usb/usbai.h> header file is included by the <sys/usb/usba.h> header file.

USBDRV_VERSION is a macro that generates the version number from USBDRV_MAJOR_VERSION and USBDRV_MINOR_VERSION. The second argument to usb_client_attach() must be USBDRV_VERSION. The usb_client_attach() function fails if the second argument is not USBDRV_VERSION or if USBDRV_VERSION reflects an invalid version. This restriction ensures programming interface compatibility.

The usb_get_dev_data() function returns information that is required for proper USB device management. For example, the usb_get_dev_data() function returns the following information:

The call to the usb_get_dev_data() function is mandatory. Calling usb_get_dev_data() is the only way to retrieve the default control pipe and retrieve the iblock_cookie required for mutex initialization.

After calling usb_get_dev_data(), the client driver's attach(9E) routine typically copies the desired descriptors and data from the descriptor tree to the driver's soft state. Endpoint descriptors copied to the soft state are used later to open pipes to those endpoints. The attach(9E) routine usually calls usb_free_descr_tree(9F) to free the descriptor tree after copying descriptors. Alternatively, you might choose to keep the descriptor tree and not copy the descriptors.

Specify one of the following three parse levels to the usb_get_dev_data(9F) function to request the breadth of the descriptor tree you want returned. You need greater tree breadth if your driver needs to bind to more of the device.

The client driver's detach(9E) routine must call the usb_free_dev_data(9F) function to release all resources allocated by theusb_get_dev_data() function. The usb_free_dev_data() function accepts handles where the descriptor tree has already been freed with the usb_free_descr_tree() function. The client driver's detach() routine also must call the usb_client_detach(9F) function to release all resources allocated by the usb_client_attach(9F) function.