While most driver operations can be performed without synchronization and protection mechanisms beyond those provided by the locking primitives described in "Multithreading Additions to the State Structure", some devices require that a sequence of events happen in order without interruption. In conjunction with the locking primitives, the function ddi_enter_critical(9F) asks the system to guarantee, to the best of its ability, that the current thread will neither be pre-empted nor interrupted. This stays in effect until a closing call to ddi_exit_critical(9F) is made. See ddi_enter_critical(9F) for details.
Many chips specify that they can be accessed only at specified intervals. For example, the Zilog Z8530 SCC has a "write recovery time" of 1.6 microseconds. This means that a delay must be enforced with drv_usecwait(9F) when writing characters with an 8530. In some instances, it is unclear what delays are needed; in such cases, they must be determined empirically.
The Intel 8251A and the Signetics 2651 alternate the same external register between two internal mode registers. Writing to the first internal register is accomplished by writing to the external register. This write, however, has the side effect of setting up the sequencing logic in the chip so that the next read/write operation refers to the second internal register.
The NEC PD7201 PCC has multiple internal data registers. To write a byte into a particular register, two steps must be performed. The first step is to write into register zero the number of the register into which the following byte of data will go. The data is then written to the specified data register. The sequencing logic automatically sets up the chip so that the next byte sent will go into data register zero.
The AMD 9513 timer has a data pointer register that points at the data register into which a data byte will go. When sending a byte to the data register, the pointer is incremented. The current value of the pointer register cannot be read.
A controller interrupt does not necessarily indicate that both the controller and one of its slave devices are ready. For some controllers, an interrupt may indicate that either the controller is ready or one of its devices is ready, but not both.
Not all devices power up with interrupts disabled and then start interrupting only when told to do so.
Some devices do not provide a way to determine that the board has generated an interrupt.
Not all interrupting boards shut off interrupts when told to do so or after a bus reset.
To achieve the goal of multiple platform, multiple instruction set architecture portability, host bus dependencies were removed from the drivers. The first dependency issue to be addressed was the endian-ness (or byte ordering) of the processor. For example, the x86 processor family is little endian while the SPARC architecture is big endian.
Bus architectures display the same endian-ness types as processors. The PCI local bus, for example, is little endian, the SBus is big endian, the ISA bus is little endian and so on.
To maintain portability between processors and buses, DDI-compliant drivers must be endian neutral. Although drivers could conceivably manage their endian-ness by runtime checks or by preprocessor directives like #ifdef _LITTLE_ENDIAN or _BIG_ENDIAN statements in the source code, long-term maintenance would be troublesome. The Solaris 7 DDI solution hides the endian-ness issues from the drivers as illustrated in Figure 2-5. In some cases, the DDI framework performs the byte swapping using a software approach. In other cases, where byte swapping can be done by hardware (as in memory management unit (MMU) page-level swapping or by special machine instructions), the DDI framework will take advantage of the hardware features to improve performance.
Along with being endian-neutral, portable drivers must also be independent from data ordering of the processor. Under most circumstances, data must be transferred in the sequence instructed by the driver. However, sometimes data can be merged, batched, or reordered to streamline the data transfer, as illustrated in Figure 2-6. For example, data merging may be applied to accelerate graphics display on frame buffers. Drivers have the option to advise the DDI framework to use other optimal data transfer mechanisms during the transfer.
For example, a reg property is used to represent device registers and onboard memory. The reg property is a software abstraction that describes device hardware registers; its value encodes the device register address location and size. Drivers use the reg property to access device registers.
As another example, an interrupt property is a software abstraction used to represent the device interrupt; its value encodes the device-interrupt pin number. For more information on properties, see "Properties".