SOUNDLIB reference
------------------

  SOUNDLIB structures and types
  -----------------------------


  devices.h

    SOUND_DISPATCH_ROUTINE

        typedef NTSTATUS SOUND_DISPATCH_ROUTINE(struct _LOCAL_DEVICE_INFO *, PIRP, PIO_STACK_LOCATION);

        This is a routine that processes requests for the device.  Normally
        SOUNDLIB code provides the actual entry point.


    SOUND_HW_SET_VOLUME_ROUTINE

        typedef VOID SOUND_HW_SET_VOLUME_ROUTINE(struct _LOCAL_DEVICE_INFO *);

        Set the volume for a given device.  For drivers with MIXER devices this
        will normally be SoundNoVolume as the actual volume setting is handled
        by the MIXER device code.  In this case SoundSetVolumeControlId can
        be used to relate a WAVE, MIDI or AUX device to a MIXER control Id.


    SOUND_EXCLUDE_CODE

        typedef enum {
            SoundExcludeOpen,
            SoundExcludeClose,
            SoundExcludeEnter,
            SoundExcludeLeave,
            SoundExcludeQueryOpen
        } SOUND_EXCLUDE_CODE;

        SoundExcludeOpen      The device is being opened
        SoundExcludeClose     The devices is being closed
        SoundExcludeEnter     A request for this device is starting
        SoundExcludeLeave     The request has finished
        SoundExcludeQueryOpen Is the device open?



    SOUND_EXCLUDE_ROUTINE

        typedef BOOLEAN SOUND_EXCLUDE_ROUTINE(struct _LOCAL_DEVICE_INFO *,
                                              SOUND_EXCLUDE_CODE);

        This routine is called by the SOUNDLIB dispatch routines for the various
        devices when a device resource needs to be serialized.

        A SOUND_EXCLUDE_CODE parameter is passed:

        SoundExcludeOpen and SoundExcludeClose request and release serial
        reuse of the device.

        SoundExcludeEnter and SoundExcludeLeave request temporary
        synchronization to the device.  Normally these are implemented by
        the driver using a MUTEX object.


    SOUND_DEVICE_INIT

        typedef struct {
            PCWSTR LeftVolumeName, RightVolumeName;
            ULONG DefaultVolume;

            ULONG Type;
            ULONG DeviceType;
            char  Key[4];
            PCWSTR PrototypeName;

            PIO_DPC_ROUTINE DeferredRoutine;

            SOUND_EXCLUDE_ROUTINE *ExclusionRoutine;
            SOUND_DISPATCH_ROUTINE *DispatchRoutine;

            SOUND_DISPATCH_ROUTINE *DevCapsRoutine;
            SOUND_HW_SET_VOLUME_ROUTINE *HwSetVolume;
            ULONG IoMethod;
        } SOUND_DEVICE_INIT;
        typedef SOUND_DEVICE_INIT CONST * PCSOUND_DEVICE_INIT;

        This structure is passed to SoundCreateDevice to set up a device.
        The data must not be freed and must be non-pated as SoundCreateDevice
        does just keeps a copy of the data passed to it.

        LeftVolumeName   Name for saving the volume setting for the left channel
                         in the registry.  Not required for devices with
                         MIXERs.

        RightVolumeName  Name for saving the volume setting for the right channel
                         in the registry.  Not required for devices with
                         MIXERs.

        DefaultVolume    Initial volume setting on install.  Note required
                         for devices with MIXERs.

        Type             Type of device.  This is passed to IoCreateDevice
                         by SoundCreateDevice:

                         FILE_DEVICE_WAVE_IN  for wave input
                         FILE_DEVICE_WAVE_OUT for wave output
                         FILE_DEVICE_MIDI_IN  for MIDI input
                         FILE_DEVICE_MIDI_OUT for MIDI output
                         FILE_DEVICE_SOUND    for everthing else

        DeviceType       Type used by SOUNDLIB and DRVLIB code.
                         (See soundcfg.h) :


                         WAVE_IN       Wave in device
                         WAVE_OUT      Wave out device
                         MIDI_IN       Midi in device
                         MIDI_OUT      Midi out device
                         AUX_DEVICE    aux device
                         MIXER_DEVICE  Mixer device
                         SYNTH_DEVICE  Synth device (adlib or opl3)

                         These values are used in the registry to tell
                         the DRVLIB code in the driver DLL which type of
                         device each device name refers to.

        Key              Debugging.  This value is put at the head of
                         the LOCAL_DEVICE_INFO structure for the device.

        PrototypeName    Name to use to create device name.
                         SoundCreateDevice will either try to use this
                         name as the device name or append a number starting
                         at 0 to it and increments it until it finds a free
                         name - see the CreationFlags parameter of
                         SoundCreateDevice.

        DeferredRoutine  For devices that support interrupts this is the
                         deferred procedure call routine.  This is normally
                         either NULL (eg for MIXER, AUX and MIDI output devices)
                         or a routine supplied by SOUNDLIB.

        ExclusionRoutine Called for mutual exclusion on the device - see
                         SOUND_EXCLUDE_ROUTINE.

        DispatchRoutine  Called when there is a device request for the device.
                         Normally a SOUNDLIB supplied routine.

        HwSetVolume      Sets the volume for the device.  For devices with
                         MIXERs or no volume setting capability use
                         SoundNoVolume.  See SOUND_HW_SET_VOLUME_ROUTINE.

        IoMethod         Determines the way the IO subsystem handles read
                         and write requests for the device.

                         Wave input     DO_DIRECT_IO
                         Wave output    DO_DIRECT_IO
                         Midi input     DO_DIRECT_IO
                         Midi output    DO_DIRECT_IO
                         Aux            DO_BUFFERED_IO
                         Mixer          DO_BUFFERED_IO

    PSOUND_LINE_NOTIFY


        typedef VOID (* PSOUND_LINE_NOTIFY)(struct _LOCAL_DEVICE_INFO *, UCHAR);

        LOCAL_DEVICE_INFO is always for a MIXER device.  This routine is called
        by device code when a line status changes between active and inactive.

        See SoundSetLineNotify.


     LOCAL_DEVICE_INFO


        typedef struct _LOCAL_DEVICE_INFO {
            ULONG           Key;
        #define LDI_WAVE_IN_KEY     (*(ULONG *)"LDWi")
        #define LDI_WAVE_OUT_KEY    (*(ULONG *)"LDWo")
        #define LDI_MIDI_IN_KEY     (*(ULONG *)"LDMi")
        #define LDI_MIDI_OUT_KEY    (*(ULONG *)"LDMo")
        #define LDI_AUX_KEY         (*(ULONG *)"LDAx")
        #define LDI_MIX_KEY         (*(ULONG *)"LDMx")

            PVOID           pGlobalInfo;
            UCHAR           DeviceType;
            UCHAR           DeviceNumber;
            UCHAR           DeviceIndex;
            UCHAR           CreationFlags;
        #define SOUND_CREATION_NO_NAME_RANGE ((UCHAR)0x01)
        #define SOUND_CREATION_NO_VOLUME     ((UCHAR)0x02)

            BOOLEAN         PreventVolumeSetting;

            UCHAR           VolumeControlId;

            PSOUND_LINE_NOTIFY
                            LineNotify;
            WAVE_DD_VOLUME  Volume;
            LIST_ENTRY      VolumeQueue;


            struct _LOCAL_DEVICE_INFO *
                            MixerDevice;
            BOOLEAN         VolumeChanged;
            PVOID           DeviceSpecificData;
            PVOID           HwContext;
            ULONG           State;
            PCSOUND_DEVICE_INIT
                            DeviceInit;
        } LOCAL_DEVICE_INFO, *PLOCAL_DEVICE_INFO;


        This struture is initialized by SoundCreateDevice.  It must be
        allocated from non-paged memory.

        There is one LOCAL_DEVICE_INFO structure for each device.  This
        because the DeviceExtension member of the DEVICE_OBJECT structure
        for the device.

        pGlobalInfo          A reference back to global driver or card instance
                             data (pGDI parameter of SoundCreateDevice).

        DeviceType           Same as DeviceType in SOUND_DEVICE_INIT
        DeviceNumber         Used internally by SOUNDLIB code to generate
                             the device name.  Is 0xFF if no number is appended
                             to the ProtoTypeName member of the SOUND_DEVICE_INIT
                             structure.

        DeviceIndex          Passed as 'i' parameter in SoundCreateDevice.  Can
                             be used to identify the device uniquely internally.

        CreationFlags        CreationFlags passed to SoundCreateDevice:

                             SOUND_CREATION_NO_NAME_RANGE  Don't append number
                                                           to prototype name.
                             SOUND_CREATION_NO_VOLUME      If volume setting not
                                                           supported.

        PreventVolumeSetting Used internally to prevent volume being set
                             on devices opened without share access on write.

        VolumeControlId      Set by SoundSetVolumeControlId.

        LineNotify           Set by SoundSetLineNotify.

        VolumeQueue          List of SOUND_IOCTL_GET_CHANGED_VOLUME requests
                             not completed.

        MixerDevice          Pointer to the MIXER device for the card instance
                             if there is one.  This MUST be set by the mixer
                             initialization code, it is not set by SOUNDLIB.

        VolumeChanged        If there is no mixer device used internally to
                             track whether volume settings need to be
                             updated in the Registry on system shutdown.

        DeviceSpecificData   Copy of DeviceSpecificData passed to
                             SoundCreateDevice.

        HwContext            Copy of pHw passed to SoundCreateDevice.

        State                Used internally for sound device types.

        DeviceInit           Copy of DeviceInit passed to SoundCreateDevice.


  soundlib.h


    SOUND_REGISTRY_CALLBACK_ROUTINE

        typedef NTSTATUS
            SOUND_REGISTRY_CALLBACK_ROUTINE(PWSTR RegistryPathName, PVOID Context);


        This routine is called by SoundEnumSubkeys for each subkey found.

        RegistryPathName   Full path to the subkey

        Context            Context passed to SoundEnumSubkeys


  wave.h

    SOUND_DMA_BUFFER

        typedef struct {
            PADAPTER_OBJECT      AdapterObject[2];
            ULONG                BufferSize;
            PVOID                VirtualAddress;
            PHYSICAL_ADDRESS     LogicalAddress;
            PMDL                 Mdl;
        } SOUND_DMA_BUFFER, *PSOUND_DMA_BUFFER;


        Internal structure used by the wave device code.


    SOUND_DOUBLE_BUFFER

        typedef struct {
            enum {LowerHalf = 0,
                  UpperHalf}
                                 NextHalf;
            ULONG                BufferSize;
            PUCHAR               Buf;
            ULONG                StartOfData;
            ULONG                nBytes;
            UCHAR                Pad;
        } SOUND_DOUBLE_BUFFER, *PSOUND_DOUBLE_BUFFER;

        Internal structure used by the wave device code.


    SOUND_BUFFER_QUEUE

        typedef struct {
            LIST_ENTRY      QueueHead;
            ULONG           BytesProcessed;
            ULONG           UserBufferSize;
            ULONG           UserBufferPosition;
            PUCHAR          UserBuffer;
            PIRP            pIrp;
            LIST_ENTRY      ProgressQueue;
        } SOUND_BUFFER_QUEUE, *PSOUND_BUFFER_QUEUE;

        Internal structure used by the wave device code.


    WAVE_INTERFACE_ROUTINE

        typedef BOOLEAN WAVE_INTERFACE_ROUTINE(struct _WAVE_INFO *);

        Type definition for callbacks to set the hardware  (See WAVE_INFO).

    SOUND_QUERY_FORMAT_ROUTINE

        typedef NTSTATUS SOUND_QUERY_FORMAT_ROUTINE (PLOCAL_DEVICE_INFO, PPCMWAVEFORMAT);

        Callback to find out if the wave format is supported.  Although the
        type specified here is PPCMWAVEFORMAT in fact any PWAVEFORMATEX is
        passed.


    enum {
        SoundNoDMA,
        SoundAutoInitDMA,             // Use autoinitialize
        SoundReprogramOnInterruptDMA, // Reprogram on interrupt
        Sound2ChannelDMA              // Keep 2 channels going
    };

        Type of DMA to support.  Sound2ChannelDMA is not supported in the
        wave device code but is meant for a device that uses 2 DMA channels
        and alternates between them in hardware to achieve continuous sound.


    WAVE_INFO

        typedef struct _WAVE_INFO {
            ULONG                   Key;
        #define WAVE_INFO_KEY       (*(ULONG *)"Wave")

            PDEVICE_OBJECT          DeviceObject;
            SOUND_DMA_BUFFER        DMABuf;
            SOUND_DOUBLE_BUFFER     DoubleBuffer;
            SOUND_BUFFER_QUEUE      BufferQueue;
            ULONG                   SamplesPerSec;
            UCHAR                   BitsPerSample;
            UCHAR                   Channels;
            BOOLEAN                 FormatChanged;

            PWAVEFORMATEX           WaveFormat;
            BOOLEAN                 LowPrioritySaved;
            PFILE_OBJECT            LowPriorityHandle;
            PLOCAL_DEVICE_INFO      LowPriorityDevice;
            struct {
                SOUND_BUFFER_QUEUE      BufferQueue;
                ULONG                   SamplesPerSec;
                UCHAR                   BitsPerSample;
                UCHAR                   Channels;

                PWAVEFORMATEX           WaveFormat;
                ULONG                   State;
            } LowPriorityModeSave;
            PVOID                   MRB[2];
            KEVENT                  DmaSetupEvent;
            KEVENT                  DpcEvent;
            KEVENT                  TimerDpcEvent;
            KSPIN_LOCK              DeviceSpinLock;
        #if DBG
            BOOLEAN                 LockHeld;
        #endif
            PKINTERRUPT             Interrupt;
            BOOLEAN                 Direction;
            UCHAR                   DMAType;
            UCHAR                   InterruptHalf;
            volatile BOOLEAN        DMABusy;
            volatile BOOLEAN        DpcQueued;
            ULONG                   Overrun;
            PVOID                   HwContext;
            WORK_QUEUE_ITEM         WaveStopWorkItem;
            KEVENT                  WaveReallyComplete;
            PSOUND_QUERY_FORMAT_ROUTINE QueryFormat;
            PWAVE_INTERFACE_ROUTINE
                                    HwSetupDMA,
                                    HwStopDMA,
                                    HwSetWaveFormat;
            KDPC                    TimerDpc;
            KTIMER                  DeviceCheckTimer;
            BOOLEAN                 GotWaveDpc;
            BOOLEAN                 DeviceBad;
            BOOLEAN                 TimerActive;
            UCHAR                   FailureCount;
        } WAVE_INFO, *PWAVE_INFO;

        This is the context for all the wave device code.  One WAVE_INFO
        structure can support wave input and output serially but not in
        parallel.  If the sound card cannot support wave input and wave
        output simultaneously the the same WAVE_INFO structure can be
        passed to SoundCreateDevice for both wave input and wave output
        devices.  In this case the SoundExcludeRoutine must obviously
        disallow both devices being open simultaneously.  If simultanous
        wave input and output are possible then different WAVE_INFO
        structures are required for wave input and wave output devices.

        The SOUNDLIB code supports low priority mode which allows a
        wave input device nominate itself to be preemptible by other
        input and output then resume.  Only one user can be in low
        priority mode at a time.

        Key                   Debugging - should be "Wave"

        DMABuf                Internal management of DMA hardware

        DoubleBuffer          Internal management of DMA data

        BufferQueue           Internal management of queue of device requests

        SamplesPerSec         Current samples per second

        BitsPerSample         Current Bits per sample (per channel)

        Channels              Current number of channels

        FormatChanged         Set before calling the HwSetWaveFormat member
                              if the format has actually changed since
                              HwSetWaveFormat was last called.

        WaveFormat            Format for Non-PCM formats

        LowPrioritySaved      Low priority mode management

        LowPriorityHandle     Low priority mode management

        LowPriorityModeSave   Low priority mode management

        MRB                   DMA internal

        DmaSetupEvent         Internal synchronziation

        DpcEvent              Internal synchronization with Dpc termination

        TimerDpcEvent         Internal - track rogue devices.

        DeviceSpinLock        Internal - Dpc routine synchronzation

        LockHeld              Internal - debugging

        Interrupt             The interrupt being used

        Direction             TRUE = output, FALSE = input

        DMAType               See Sound...DMA definitions above.

        InterruptHalf         Not used

        DMABusy               Internal

        DpcQueued             Overrun detection.  This should be set in the ISR
                              just before IoRequestDpc is called.  If is
                              already set the overrun has occurred and no Dpc should
                              be queued.

        Overrun               Set if overrun occurs.

        HwContext             Context to be passed to Hw... routines.

        WaveStopWorkItem      Internal.  This work item is queued when DMA
                              completes.  The HwStopDMA member is called from
                              the ExWorker thread so that it can wait for
                              slow devices if necessary.

        WaveReallyComplete    Internal.
                              Set in the ExWorker thread when HwStopDMA has
                              been called.

        QueryFormat           Call back to see if a proposed format is
                              supported.

        HwSetupDMA            Called when the DMA registers have been
                              initialized and the hardware should be told to
                              start its DMA.

        HwStopDMA             Called when DMA should stop but before the
                              DMA hardware has been shut down.

        HwSetWaveFormat       Called just before the DMA registers are
                              initialized to commence DMA.

        TimerDpc              Internal.  Used to stop rogue devices.

        DeviceCheckTimer      Internal.  Used to stop rogue devices.

        DeviceBad             Internal.  Used to stop rogue devices.

        TimerActive           Internal.  Used to stop rogue devices.

        FailureCount          Internal.  Used to stop rogue devices.



  midi.h


    MIDI_INTERFACE_ROUTINE

        typedef BOOLEAN MIDI_INTERFACE_ROUTINE(struct _MIDI_INFO *);

        Type for callbacks

    MIDI_INFO

        typedef struct _MIDI_INFO {
            ULONG           Key;
        #define MIDI_INFO_KEY       (*(ULONG *)"Midi")

            KSPIN_LOCK      DeviceSpinLock;

        #if DBG
            BOOLEAN         LockHeld;
        #endif

            LARGE_INTEGER   RefTime;
            LIST_ENTRY      QueueHead;
            PVOID           HwContext;
            PMIDI_INTERFACE_ROUTINE
                            HwStartMidiIn,
                            HwStopMidiIn;
            BOOLEAN      (* HwMidiRead)(
                                struct _MIDI_INFO *, PUCHAR);
            VOID         (* HwMidiOut)(
                                struct _MIDI_INFO *, PUCHAR, int);
            BOOLEAN         fMidiInStarted;
            UCHAR           InputPosition;
            UCHAR           InputBytes;
            UCHAR           MidiInputByte[64];
        } MIDI_INFO, *PMIDI_INFO;

        A single MIDI_INFO structure can be used to support simultaneous
        MIDI input and output.

        A MIDI_INFO structure is passed as the DeviceSpecificData parameter
        for SoundCreateDevice for external midi input and output devices.  For
        synthsizer devices see below.

        Key              Debugging ( = "Midi")

        DeviceSpinLock   Internal. Synchronization with Dpc for MIDI input.

        LockHeld         Internal. Debugging.

        RefTime          Internal.  Midi input Timing.

        QueueHead        Internal queue of requests for MIDI input.

        HwContext        Context to pass to Hw... routines.

        HwStartMidiIn    Start reading MIDI input from external source.

        HwStopMidiIn     Stop reading MIDI input from exteranl source.

        HwMidiRead       Read the next byte of MIDI input (or return FALSE
                         if there isn't one).

        HwMidiOut        Sent out a string of MIDI bytes.

        fMidiInStarted   Internal.  MIDI input running.

        InputPosition    Internal.  Manage buffer.

        InputBytes       Internal.  Manage buffer.

        MidiInputByte    Internal.  Buffer of input bytes.


  mixer.h

    For an understanding of the MIXER API refer to the Win32 SDK documetation.

    PMIXER_DD_GET_SET_DATA

        typedef NTSTATUS (* PMIXER_DD_GET_SET_DATA)(struct _MIXER_INFO * MixerInfo,
                                                    ULONG  Id,
                                                    ULONG  Length,
                                                    PVOID  Data);

        Callback type for getting and setting actual mixer data.


        MixerInfo         MIXER_INFO structure for this mixer.

        Id                For HwGetLineData a mixer Line Id.
                          For HwGetControlData, HwGetCombinedControlData,
                          HwSetControlData a Control Id.

        Length            Length of data.

        Data              The data.




    MIXER_INFO

        typedef struct _MIXER_INFO {
            ULONG    Key;
        #define MIX_INFO_KEY       (*(ULONG *)"Mix")

            UCHAR         NumberOfLines;
            UCHAR         NumberOfControls;
            LARGE_INTEGER CurrentLogicalTime;
            LIST_ENTRY    NotifyQueue;
            LIST_ENTRY    ChangedItems;
            PMIXER_DD_GET_SET_DATA HwGetLineData;
            PMIXER_DD_GET_SET_DATA HwGetControlData;
            PMIXER_DD_GET_SET_DATA HwGetCombinedControlData;
            PMIXER_DD_GET_SET_DATA HwSetControlData;
        } MIXER_INFO, *PMIXER_INFO;

        A MIXER_INFO structure is passed as the DeviceSpecificdata parameter
        to SoundCreateDevice for Mixer devices.


        Key                  Debugging (= "Mix")

        NumberOfLines        Number of mixer lines

        NumberOfControls     Number of mixer controls

        CurrentLogicalTime   Internal.  Control sending of notifications.

        NotifyQueue          Internal.  Control sending of notifications.

        ChangedItems         Internal.  Control sending of notifications.

        HwGetLineData        Retrieve line flags (See definition of
                             PMIXER_DD_GET_SET_DATA):

                             Length     sizeof(ULONG)

                             Data       pointer to a ULONG of flags

                                        MIXERLINE_LINEF_ACTIVE - line is active
                                        (mainly for wave devices so that the
                                        application knows when to poll the
                                        peak meter)

                                        MIXERLINE_LINEF_DISCONNECTED - the
                                        line is permanently unavailable

                                        MIXERLINE_LINEF_SOURCE - this is a
                                        source line (rather than a destination).

        HwGetControlData     Retrieve the information for a given control
                             (see the definition of PMIXER_DD_GET_SET_DATA):

                             Length     length of control data to return.
                                        For multiple channel or multiple
                                        item controls this can either be
                                        the length of all the control items
                                        or just one.  If it's the length of
                                        just one then the control values
                                        should be combined in a meaningful
                                        way depending on the control type -
                                        eg maximum for volume.

                             Data       Where to put the control data

        HwGetCombinedControlData Retrieve the combined information for a given
                             control.  This will only ever be used for volume
                             controls.  If the mixer supports volume setting
                             in hardware then just return 0xFFFF for all
                             channels.  Otherwise if the master volume is
                             supported in hardware return the current value of
                             the control.  If the master volume is simulated
                             return the combined volume and master volume as
                             a volume value.

                             (see the definition of PMIXER_DD_GET_SET_DATA):

                             Length     length of control data to return.
                                        For multiple channel or multiple
                                        item controls this can either be
                                        the length of all the control items
                                        or just one.  If it's the length of
                                        just one then the control values
                                        should be combined in a meaningful
                                        way depending on the control type -
                                        eg maximum for volume.

                             Data       Where to put the control data

        HwSetControlData     Set the information for a given control
                             (see the definition of PMIXER_DD_GET_SET_DATA):

                             Length     length of control data.
                                        For multiple channel or multiple
                                        item controls this can either be
                                        the length of all the control items
                                        or just one.  If it's the length of
                                        just one then the control value
                                        should be interpreted in a meaningful
                                        way depending on the control type -
                                        eg set all values to this value for
                                        volume.

                             Data       The new value.

                             If the value of a control changes then
                             SoundMixerChangedItem should be called to
                             notify SOUNDLIB to dispatch any waiters for this
                             mixer.  (See also SoundInitDataItem which sets
                             this mechanism up).


    MIXER_DATA_ITEM

        typedef struct _MIXER_DATA_ITEM {
            LIST_ENTRY    Entry;
            LARGE_INTEGER LastSet;
            USHORT        Message;
            USHORT        Id;
        } MIXER_DATA_ITEM, *PMIXER_DATA_ITEM;

        Data item entry to control application notification.  See
        SoundInitDataItem and SoundMixerChangedItem.


  synthdrv.h


        typedef enum {
           AdlibDevice = 5,
           Opl3Device
        }

        Types of synthesizer device.


        typedef struct {
            ULONG           Key;                // For debugging
        #define SYNTH_HARDWARE_KEY        (*(ULONG *)"Hw  ")

            PUCHAR          SynthBase;          // base port address for synth

        } SYNTH_HARDWARE, *PSYNTH_HARDWARE;

        Internal SOUNDLIB.


        typedef struct _GLOBAL_SYNTH_INFO {
            ULONG           Key;
        #define SYNTH_KEY        (*(ULONG *)"Syn ")
            INTERFACE_TYPE  BusType;
            ULONG           BusNumber;
            KMUTEX          MidiMutex;
            ULONG           MemType;
            PDEVICE_OBJECT  DeviceObject;
            PDRIVER_OBJECT  DriverObject;
            SOUND_DISPATCH_ROUTINE
                            *DevCapsRoutine;
            UCHAR           DeviceInUse;
            volatile BOOLEAN
                            InterruptFired;     // Interrupt fired?
            BOOLEAN         IsOpl3;             // It's an OPL3
            SYNTH_HARDWARE  Hw;                 // Hardware specific stuff
        } GLOBAL_SYNTH_INFO, *PGLOBAL_SYNTH_INFO;

        Mainly internal to SOUNDLIB - see definition of SynthInit.


  SOUNDLIB Functions
  ------------------


    SOUND_DISPATCH_ROUTINE
        SoundAuxDispatch,
        SoundMidiDispatch,
        SoundWaveDispatch,
        SoundMixerDispatch

    These are the dispatch routines for the device handling in SOUNDLIB.
    The appropriate routine address should be set in the DispatchRoutine member
    of the SOUND_DEVICE_INIT structure passed to SoundCreateDevice.


    VOID
    SoundWaveDeferred(
        PKDPC pDpc,
        PDEVICE_OBJECT pDeviceObject,
        PIRP pIrp,
        PVOID Context
    )

    This is the SOUNDLIB Dpc routine used by the wave support in SOUNDLIB.
    For wave devices this routine address should be set in the DeferredRoutine
    member of the SOUND_DEVICE_INIT structure passed to SoundCreateDevice.

    VOID
    SoundMidiInDeferred(
        IN     PKDPC pDpc,
        IN     PDEVICE_OBJECT pDeviceObject,
        IN OUT PIRP pIrpDeferred,
        IN OUT PVOID Context
    )

    This is the SOUNDLIB Dpc routine used by the midi input support in SOUNDLIB.
    For wave devices this routine address should be set in the DeferredRoutine
    member of the SOUND_DEVICE_INIT structure passed to SoundCreateDevice.

    NTSTATUS
    SoundDispatch(
        IN    PDEVICE_OBJECT pDO,
        IN    PIRP pIrp
    )

    This is the SOUNDLIB main dispatch routine.  The following entry points
    in the driver object's dispatch table should point to it:

        IRP_MJ_CLEANUP
        IRP_MJ_CLOSE
        IRP_MJ_CREATE
        IRP_MJ_DEVICE_CONTROL
        IRP_MJ_READ
        IRP_MJ_WRITE


    NTSTATUS
    SoundSetShareAccess(
        IN OUT PLOCAL_DEVICE_INFO pLDI,
        IN     PIO_STACK_LOCATION IrpStack
    )

    This is an internal SOUNDLIB function.


    SOUND_HW_SET_VOLUME_ROUTINE SoundNoVolume

    This can be used for the HwSetVolume member of SOUND_DEVICE_INIT when
    the device either doesn't support volume setting or the volume is
    controlled by a mixer.


    VOID
    SoundSaveDeviceVolume(
       PLOCAL_DEVICE_INFO pLDI,
       PWSTR KeyName
    )


    Save a volume setting.  This should be called at shutdown time or
    when the driver is unloaded.  This routine is not used if the volume
    is controlled by a mixer.

    pLDI           This device's device info.  Same as the DeviceExtension
                   member of the device's DEVICE_OBJECT structure.

    KeyName        The registry key to store it under.  The value names
                   is retrieved from the LeftVolumeName and
                   RightVolumeName members of the DeviceInit member of pLDI.



    NTSTATUS
    SoundGetBusNumber(
        IN OUT  INTERFACE_TYPE InterfaceType,
        OUT PULONG BusNumber
    )

    Find the first number of the first bus of type InterfaceType.

    InterfaceType        Type of bus to search for.

    BusNumber            Bus number to return

    Returns STATUS_SUCCESS if successful, otherwise an NTSTATUS code.


    NTSTATUS SoundReportResourceUsage(
        IN PDEVICE_OBJECT DeviceObject,
        IN INTERFACE_TYPE BusType,
        IN ULONG BusNumber,
        IN PULONG InterruptNumber OPTIONAL,
        IN KINTERRUPT_MODE InterruptMode,
        IN BOOLEAN InterruptShareDisposition,
        IN PULONG DmaChannel OPTIONAL,
        IN PULONG FirstIoPort OPTIONAL,
        IN ULONG IoPortLength
    )

    Reports resources in use to the system.  Overwrites any previous resources
    reported on the same DeviceObject.

    DeviceObject              Either a DEVICE_OBJECT or DRIVER_OBJECT structure.  Use
                              DEVICE_OBJECT structures for stuff which is meant to be
                              permanent because this works better when supporting
                              multiple cards.

    BusType                   Type of bus the card is on.

    BusNumber                 Number of the bus the card is on.

    InterruptNumber           Pointer to the interrupt number, or NULL if no interrupt.

    InterruptMode             Interrupt mode (Latched or LevelSensitive) if InterruptNumber
                              is not NULL, otherwise ignored.

    InterruptShareDisposition TRUE if interrupt can be shared.  FALSE otherwise.
                              Ignored if InterruptNumber is NULL.

    DmaChannel                DMA channel to report or NULL if no DMA channel
                              is being reported.

    FirstIoPort               IO address or NULL if no IO address is being
                              reported.

    IoPortLength              Number of IO ports.
                              Ignored if FirstIoPort is NULL.

    Returns STATUS_SUCCESS if successful, otherwise an NTSTATUS code which
            usually means one of resources is in use by another driver.


    VOID
    SoundFreeDevice(
        IN  PDEVICE_OBJECT DeviceObject
    )

    Free the device and release unreport any resources reported on the
    device object.


    NTSTATUS
    SoundCreateDevice(
        IN   PCSOUND_DEVICE_INIT DeviceInit,
        IN   UCHAR CreationFlags,
        IN   PDRIVER_OBJECT pDriverObject,
        IN   PVOID pGDI,
        IN   PVOID DeviceSpecificData,
        IN   PVOID pHw,
        IN   int i,
        OUT  PDEVICE_OBJECT *ppDevObj
    )

    Creates a new device object complete with dispatch routine.  The
    new device's DeviceExtension member of its DEVICE_OBJECT structure
    will be a LOCAL_DEVICE_INFO structure.

    DeviceInit           Initialized SOUND_DEVICE_INIT structure.  Must
                         not be freed until after the device is freed.
                         Must note be pageable.

    CreationFlags        Flags:

                             SOUND_CREATION_NO_NAME_RANGE  Don't append number
                                                           to prototype name.
                             SOUND_CREATION_NO_VOLUME      If volume setting not
                                                           supported.

    pDriverObject        Driver object passed to DriverEntry routine.

    pGDI                 Global info - will be stored in the pGlobalInfo
                         of the LOCAL_DEVICE_INFO structure for the device.

    DeviceSpecific       Data structure relevant to the specific device:

                         WAVE_INFO   For wave devices
                         MIDI_INFO   For MIDI devices
                         MIXER_INFO  For mixer devices
                         NULL        Otherwise

    pHw                  Hardware context.  Stored in HwContext of
                         PLOCAL_DEVICE_INFO.

    i                    Stored as DeviceIndex in LOCAL_DEVICE_INFO.

    ppDevObj             New DEVICE_OBJECT structure for device if successful.


    Returns  STATUS_SUCCESS if successful, otherwise an NTSTATUS code.


    NTSTATUS
    SoundSaveDeviceName(
        IN     PWSTR RegistryPathName,
        IN     PLOCAL_DEVICE_INFO pLDI
    )

    Save the device name in the Devices subkey of the card instance subkey of
    the Parameters key of the driver's services node.

    RegistryPathName      Full path to the card instance subkey.

    pLDI                  LOCAL_DEVICE_INFO for the device.


    NTSTATUS
    SoundCreateDeviceName(
        PCWSTR PrePrefix,
        PCWSTR Prefix,
        UCHAR  Index,
        PUNICODE_STRING DeviceName
    )

    This is an internal SOUNDLIB function.
    Create the device name (eg "\\Device\\SBWaveOut0") given the component
    parts.

    PrePrefix     A prefix to append to the prefix - \Device\ or \DosDevices\

    Prefix        Main part of the name - SBWaveOut

    Index         A number to append to the name or 0xFF in which case no
                  number is appended.


    NTSTATUS
    SoundEnumSubkeys(
        IN   PUNICODE_STRING                  RegistryPathName,
        IN   PWSTR                            Subkey,
        IN   PSOUND_REGISTRY_CALLBACK_ROUTINE Callback,
        IN   PVOID                            Context
    )

    Walk the subkeys of the Parameters key of the services node calling the
    card instance initialization.

    RegistryPathName        Full path to the driver's services node.

    SubKey                  Usually "Parameters"

    Callback                Card instance init routine.

    Context                 Context parameter to pass to Callback,


    NTSTATUS
    SoundOpenDevicesKey(
        IN   PWSTR RegistryPathName,
        OUT  PHANDLE DevicesKey
    )

    Open the devices key.  This is necessary during cleanup when configuration
    fails.  In this case the key should be deleted using ZwDeleteKey, the
    closed using ZwClose.  Otherwise the DRVLIB code gets confused about which
    devices are available.


    PUCHAR
    SoundMapPortAddress(
        INTERFACE_TYPE BusType,
        ULONG BusNumber,
        ULONG PortBase,
        ULONG Length,
        PULONG MemType
    )

    Turn an IO address into a pointer suitable for using in the HAL Port IO
    routines (READ_PORT_UCHAR etc).  If the output MemType is 0 the during
    cleanup MmUnmapIoSpace must be called to free the mapping.

    BusType               Type of bus

    BusNumber             Number of bus

    PortBase              Port number

    Length                Number of ports

    MemType               Type of memory detected - necessary for cleanup.


    NTSTATUS
    SoundConnectInterrupt(
        IN ULONG InterruptNumber,
        IN INTERFACE_TYPE BusType,
        IN ULONG BusNumber,
        IN PKSERVICE_ROUTINE Isr,
        IN PVOID ServiceContext,
        IN KINTERRUPT_MODE InterruptMode,
        IN BOOLEAN ShareVector,
        OUT PKINTERRUPT *Interrupt
    )


    Create a KINTERRUPT object and install an interrupt handler.

    InterruptNumer        Interrupt to connect

    BusType               Type of bus

    BusNumber             Number of bus

    Isr                   Driver supplied ISR routine (see the Kernel Mode
                          Driver Design Guide).

    ServiceContext        Context for ISR

    InterruptMode         Latched or LevelSensitive.

    ShareVector           TRUE if interrupt is sharable, otherwise FALSE.

    Interrupt             Pointer to a KINTERRUPT structure in non-paged
                          memory.

    Returns an NTSTATUS code.


    NTSTATUS
    SoundSetErrorCode(
        IN   PWSTR RegistryPath,
        IN   ULONG Value
    )

    Sets a configuration return code in the "Configuration Error" value of
    the given key.

    RegistryPath          Full path to the registry key.

    Value                 Value to save.


    NTSTATUS
    SoundWriteRegistryDWORD(
        IN   PCWSTR RegistryPath,
        IN   PCWSTR ValueName,
        IN   ULONG  Value
    )

    Saves REG_DWORD value in the key given by RegistryPath under the name
    ValueName.

    RegistryPath          Full path to the registry key.

    ValueName             Name of the value to use.

    Value                 Value to store.


    VOID
    SoundEnter(
        PLOCAL_DEVICE_INFO pLDI,
        BOOLEAN            Enter
    )

    Call the SoundExcludeRoutine of the device with the SoundExcludeEnter or
    SoundExcludeLeave value.

    pLDI                  LOCAL_DEVICE_INFO for the device.

    Enter                 If TRUE use SoundExcludeEnter, otherwise
                          SoundExcludeLeave.

    VOID
    SoundDelay(
        IN ULONG Milliseconds
    )

    Wait (for slow device).

    Milliseconds         Wait at least this number of Milliseconds.


    LARGE_INTEGER
    SoundGetTime(
        VOID
    )

    Get a time value in 100 nanoseconds units.  This has very high resolution
    but may have some drift from the system time.

    Returns a time value in 100 nanoseconds units.


    VOID
    SoundFreeQ(
        PLIST_ENTRY ListHead,
        NTSTATUS IoStatus
    )

    Mainly used internally to SOUNDLIB.

    Free a list of IO Request Packets (IRPs) with the given status code.  The
    Cancel spin lock is used in case the requests are cancellable.


    VOID
    SoundAddIrpToCancellableQ(
        PLIST_ENTRY QueueHead,
        PIRP Irp,
        BOOLEAN Head
    )

    Mainly used internally to SOUNDLIB.

    Add an IRP to a queue.  On this queue the IRP can be cancelled at any
    time.

    QueueHead              Head of queue.

    Irp                    IRP.

    Head                   If TRUE add to head of queue, otherwise to tail.


    PIRP
    SoundRemoveFromCancellableQ(
        PLIST_ENTRY QueueHead
    )

    Get the top of a cancellable queue and make it non-cancellable.

    QueueHead              Head of queue.  Must be initialized with
                           InitializeListHead.

    Returns  NULL if no entry, or an IRP which is not labelled as cancellable.



    VOID
    SoundFreePendingIrps(
        PLIST_ENTRY QueueHead,
        PFILE_OBJECT FileObject
    )

    Frees all IRPs in a queue which refer to the given FILE_OBJECT.

    QueueHead              Head of queue.

    FileObject             File Object.



    VOID
    SoundVolumeNotify(
        IN OUT PLOCAL_DEVICE_INFO pLDI
    )

    Used by MIXER code to notify a device when its volume has changed.  This
    is only necessary if volume setting is controlled in software such as the
    windows sound system synthesizer.



    VOID
    SoundInitializeWaveInfo(
        PWAVE_INFO WaveInfo,
        UCHAR DMAType,
        PSOUND_QUERY_FORMAT_ROUTINE QueryFormat,
        PVOID HwContext
    )

    Set up a WAVE_INFO structure.  Note that the HwSetupDMA, HwStopDMA,
    HwSetWaveFormat members should initialized and the rest of the structure
    0 before calling this.

    WaveInfo            WAVE_INFO structure to initialize.

    DMAType             Type of DMA to use.  See Sound...DMA definitions above.

    QueryFormat         Format query routine.

    HwContext           Stored in HwContext member of WAVE_INFO.


    NTSTATUS
    SoundGetCommonBuffer(
        IN  PDEVICE_DESCRIPTION DeviceDescription,
        IN  OUT PSOUND_DMA_BUFFER SoundAutoData
    )

    Allocate a buffer for auto-initialize DMA.  If the size specified is
    not available a smaller size may be returned.

    DeviceDescription       Description of Adapter.  Must be initialized.

    SoundAutoData           Returns results.

    Returns NTSTATUS code.



    VOID
    SoundFreeCommonBuffer(
        IN OUT PSOUND_DMA_BUFFER SoundAutoData
    )

    Free the buffer allocated by SoundGetCommonBuffer.


    BOOLEAN
    SoundPeakMeter(
        IN    PWAVE_INFO WaveInfo,
        OUT   PLONG Amplitudes
    )

    Return an amplitude setting from the device.  This is done in software
    by inspecting the wave samples.

    WaveInfo               WAVE_INFO for wave device.
    Amplitudes             2 LONGs for left and right channels.  Values
                           returned are between 0 and 0xFFFF.

    ULONG
    SoundGetDMABufferSize(
        IN    PWAVE_INFO WaveInfo
    )

    Find out the actual DMA buffer size being used for the current wave
    format.  This may be smaller than the actual size available.  SOUNDLIB
    tries to set a buffer size corresponding to 1/8 of a second if there is
    sufficient space.

    WaveInfo               WAVE_INFO for wave device.


    int
    SoundTestWaveDevice(
        IN PDEVICE_OBJECT pDO
    )

    See if the wave device is working.  Used for checking interrupt and
    DMA channel values if there is no better method.



    VOID SoundInitMidiIn(
        IN OUT PMIDI_INFO pMidi,
        IN     PVOID HwContext
    )

    Initialize a MIDI_INFO structure.

    pMidi        Pointer to MIDI_INFO structure to initialize.  This should
                 be in non-paged memory.  The following members should
                 be initialized before calling SoundInitMidiIn

                 HwStartMidiIn

                 HwStopMidiIn

                 HwMidiRead

                 HwMidiOut

                 and the rest of the structure should be 0.

    HwContext    Context for Hw... callbacks.


    VOID
    SoundInitMixerInfo(
        IN OUT PMIXER_INFO     MixerInfo,
        PMIXER_DD_GET_SET_DATA HwGetLineData,
        PMIXER_DD_GET_SET_DATA HwGetControlData,
        PMIXER_DD_GET_SET_DATA HwGetCombinedControlData,
        PMIXER_DD_GET_SET_DATA HwGetSetControlData
    )

    Initialize MIXER_INFO structure.

    MixerInfo                  MIXER_INFO structure to initialize

    HwGetLineData              Callback for Line info (see HwGetLineData member
                               of MIXER_INFO).

    HwGetControlData           Callback for Line info (see HwGetControlData member
                               of MIXER_INFO).

    HwGetCombinedControlData   Callback for Line info (see HwGetControlData member
                               of MIXER_INFO).

    HwGetSetControlData        Callback for Line info (see HwSetControlData member
                               of MIXER_INFO).


    NTSTATUS
    SoundMixerDispatch(
        IN OUT PLOCAL_DEVICE_INFO pLDI,
        IN    PIRP pIrp,
        IN    PIO_STACK_LOCATION IrpStack
    )

    SOUNDLIB mixer device request handler.  Set the DispatchRoutine member
    of SOUND_DEVICE_INIT to this for mixer devices.


    VOID
    SoundSetLineNotify(
        PLOCAL_DEVICE_INFO pLDI,
        PSOUND_LINE_NOTIFY LineNotify
    )

    Register a routine to be called when the status of a line changes.  This
    is primarily for wave and midi lines where the mixer hardware may
    need setting up for play or record and mixer notifications sent.

    pLDI                LOCAL_DEVICE_INFO for the device whose state
                        changes are to be notified.

    LineNotify          Routine to call.


    VOID
    SoundSetVolumeControlId(
        PLOCAL_DEVICE_INFO pLDI,
        UCHAR              VolumeControlId
    )

    Set the control id for the volume control associated with a given device.
    This allows SOUNDLIB to keep a device's volume settings in synch with
    the mixer's settings.

    pLDI                Device whose volume is controlled.

    VolumeControlId     Id of control for controlling the device's volume.


    VOID
    SoundInitDataItem(
        PMIXER_INFO         MixerInfo,
        PMIXER_DATA_ITEM    MixerDataItem,
        USHORT              Message,
        USHORT              Id
    )

    Register a data item with the mixer.  All lines and controls must be
    registered so that notifications can be correctly generated by the
    SOUNDLIB mixer code when SoundMixerChangedItem is called.

    MixerInfo           MIXER_INFO for device.  Must have been initialized
                        with SoundInitMixerInfo.

    MixerDataItem       Item to be added to the list.

    Message             For Line type items use MM_MIXM_LINE_CHANGE
                        For control items   use MM_MIXM_CONTROL_CHANGE

    Id                  Line ID for if a line item, otherwise
                        the control id for a control item.

    VOID
    SoundMixerChangedItem(
        IN OUT PMIXER_INFO      MixerInfo,
        IN OUT PMIXER_DATA_ITEM MixerItem
    )

    Notify a change to a mixer item.

    MixerInfo           MIXER_INFO for device.  Must have been initialized
                        with SoundInitMixerInfo.

    MixerDataItem       Item which has changed.


    NTSTATUS
    SynthInit(
        IN   PDRIVER_OBJECT           pDriverObject,
        IN   PWSTR                    RegistryPathName,
        IN   PGLOBAL_SYNTH_INFO       pGDI,
        IN   ULONG                    SynthPort,
        IN   BOOLEAN                  InterruptConnected,
        IN   INTERFACE_TYPE           BusType,
        IN   ULONG                    BusNumber,
        IN   PMIXER_DATA_ITEM         MidiOutItem,
        IN   UCHAR                    VolumeControlId,
        IN   BOOLEAN                  Multiple,
        IN   SOUND_DISPATCH_ROUTINE   *DevCapsRoutine
    )

    Initialize a Synthesizer device (Ad Lib or OPL3).  Once this has been
    called the device is handled entirely by SOUNDLIB (except for possible
    interrupts which must be handled by the driver ISR).

    pDriverObject             DRIVER_OBJECT for driver.

    RegistryPathName          Card instance full registry path.

    pGDI                      A zero-initialized GLOBAL_SYNTH_INFO structure.

    SynthPort                 Port address of the synth (eg 0x388).

    InterruptConnected        Hardware will interrupt when synth timer expires.

    BusType                   Type of bus (eg Isa) hardware is on.

    BusNumber                 Number of bus hardware is on.

    MidiOutItem               Mixer item to signal if mixer controlled.

    VolumeControlId           Id for mixer control controlling synth volume.

    Multiple                  Create indexed device name or unique name
                              (use FALSE if using port 0x388).

    DevCapsRoutine            Called back to return device caps.

    Returns  NTSTATUS code.



    VOID
    SynthCleanup(
        IN   PGLOBAL_SYNTH_INFO pGDI
    )

    Clean up synth on driver unload.
