Most audio device drivers will be interrupt-driven. For example, a waveform output device interrupts when the device needs another data block. A MIDI input device interrupts when the device receives a MIDI event at its input port.
Driver code accessed during an interrupt service routine must adhere to the guidelines discussed in the following sections.
Any code segments or data segments a driver accesses at interrupt-time must be fixed segments. For best overall system performance, you should minimize the amount of code and data in fixed segments. To minimize the amount of fixed code, isolate all interrupt-time code in a few source modules and put this code into a single fixed code segment. Unless your driver has a large amount of data not accessed at interrupt time, use a single fixed data segment.
The Sound Blaster driver is a medium-model DLL, using a single data segment and multiple code segments. The following example fragment is from the module-definition file for the Sound Blaster:
CODEMOVEABLE DISCARDABLE LOADONCALL
DATAFIXED SINGLE PRELOAD
SEGMENTS
_TEXTFIXEDPRELOAD
INITMOVEABLEDISCARDABLEPRELOAD
COMMONMOVEABLEDISCARDABLEPRELOAD
WAVEMOVEABLEDISCARDABLEPRELOAD
MIDIMOVEABLEDISCARDABLEPRELOAD
This example fixes the data segment and the code segment named _TEXT. All other code segments are moveable.
The data segment _TEXT is used as a safety measure. The compiler places code for which you do not specify a segment in the _TEXT segment. This way any code that is missed will be placed into a fixed segment preventing possible problems at interrupt time. However, you should check your segmentation to ensure that only code that is required to be FIXED goes into the FIXED code segment.
You can allocate either local memory or global memory for use at interrupt time.
To allocate local memory for use at interrupt time, follow these steps:
1.Use LocalAlloc with the LMEM_FIXED flag to get a handle to the memory block.
2.Pass this handle to LocalLock to get a near pointer to the memory block.
Any global memory a driver uses at interrupt-time must be page-locked. To allocate and page-lock global memory, follow these steps:
1.Use GlobalAlloc with the GMEM_MOVEABLE and GMEM_SHARE flags to get a handle to the memory block.
2.Pass this handle to GlobalLock to get a far pointer to the memory block.
3.Pass the high-order word of the far pointer to GlobalPageLock to page-lock the memory block.
The only Windows functions a driver can call at interrupt time are PostMessage, PostAppMessage, DriverCallback, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugStr.