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:
The PROM (OBP/BIOS) and USBA framework gain access to the device before any client driver is attached.
The hub driver probes devices on each of its hub's ports for identity and configuration.
The default control pipe to each device is opened, and each device is probed for its device descriptor.
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
The dev_cfg array shown in the above figure contains nodes that correspond to
configurations. Each node contains the following information:
A parsed configuration descriptor
A pointer to an array of descriptors that correspond to the interfaces of that configuration
A pointer to an array of class-specific or vendor-specific raw data, if any exists
The node that represents the second interface of the second indexed configuration is
at dev_cfg.cfg_if 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. 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
#define USBDRV_MAJOR_VER 2
#define USBDRV_MINOR_VER minor-version
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 default control pipe
The iblock_cookie to use in mutex initializations (see mutex_init(9F))
The parsed device descriptor
The tree hierarchy as described in The Descriptor Tree
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
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
USB_PARSE_LVL_IF. If your client driver binds to a specific interface, the driver needs the descriptors for only that interface. Specify USB_PARSE_LVL_IF for the parse level in the usb_get_dev_data() call to retrieve only those descriptors.
USB_PARSE_LVL_CFG. If your client driver binds to the whole device, specify USB_PARSE_LVL_CFG to retrieve all descriptors of the current configuration.
USB_PARSE_LVL_ALL. Specify USB_PARSE_LVL_ALL to retrieve all descriptors of all configurations. For example, you need this greatest tree breadth to use usb_print_descr_tree(9F) to print a descriptor dump of all configurations of a 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.