Solaris devices are managed inside a tree-like structure called the device (devinfo) tree. Each node of the devinfo tree stores information that relates to a particular instance of a device in the system. Each leaf node corresponds to a device driver, while all other nodes are called nexus nodes. Typically, a nexus represents a bus. A bus node isolates leaf drivers from bus dependencies, which enables architecturally independent drivers to be produced.
Many of the DDI functions, particularly the data access functions (DAFs), result in upcalls to the bus nexus drivers. When a leaf driver accesses its hardware, it passes a handle to an access routine. The bus nexus understands how to manipulate the handle and fulfill the request. A DDI-compliant driver only accesses hardware through use of these DDI access routines. The test harness intercepts these upcalls before they reach the specified bus nexus. If the data access matches the criteria that is specified by the driver tester, the access will be corrupted. If the data access does not match the criteria, it is given to the bus nexus to handle in the usual way.
A driver obtains an access handle by using the ddi_map_regs_setup(dip, rset, ma, offset, size, handle) function. The arguments specify which ``offboard'' memory is to be mapped. The driver must use the returned handle when it references the mapped I/O addresses, as handles are meant to isolate drivers from the details of bus hierarchies. Therefore, do not directly use the returned mapped address, ma. Direct use of the mapped address destroys the current and future uses of the DAF mechanism.
For programmed I/O, the suite of DAFs are:
I/O to Host: ddi_getX(handle, ma) and ddi_rep_getX(handle, buf, ma, repcnt, flag)
Host to I/O: ddi_putX(handle, ma, value) and ddi_rep_putX()
X and repcnt are the number of bytes to be transferred. X is the bus transfer size of 8, 16, 32, or 64 bytes.
DMA has a similar, yet richer, set of DAFs.