//---------------------------------------------------------------------------
//
//  Module:   kmxluser.c
//
//  Description:
//    Contains the handlers for the ring 3 mixer line api functions.
//
//
//@@BEGIN_MSINTERNAL
//  Development Team:
//    D. Baumberger
//
//  History:   Date       Author      Comment
//
//@@END_MSINTERNAL
//
//---------------------------------------------------------------------------
//
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
//  PURPOSE.
//
//  Copyright (C) Microsoft Corporation, 1997 - 1999  All Rights Reserved.
//
//---------------------------------------------------------------------------

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//                                                                   //
//                          I N C L U D E S                          //
//                                                                   //
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

#include "WDMSYS.H"


FAST_MUTEX ReferenceCountMutex;
ULONG      ReferenceCount = 0;

#define NOT16( di ) if( di->dwFormat == ANSI_TAG ) DPF(DL_WARNING|FA_USER,("Invalid dwFormat.") );


#pragma PAGEABLE_CODE


///////////////////////////////////////////////////////////////////////
//
// kmxlInitializeMixer
//
// Queries SysAudio to find the number of devices and builds the mixer
// line structures for each of those devices.
//
//

NTSTATUS
kmxlInitializeMixer(
    PWDMACONTEXT pWdmaContext,
    PCWSTR DeviceInterface,
    ULONG cDevices
)
{
    NTSTATUS     Status;
    ULONG        Device;
    BOOLEAN      Error = FALSE;
//    PFILE_OBJECT pfo;
    PMIXERDEVICE pmxd;

    PAGED_CODE();

    ExInitializeFastMutex( &ReferenceCountMutex );

    DPF(DL_TRACE|FA_USER, ("Found %d mixer devices for DI: %ls", cDevices, DeviceInterface));


    //
    // Current limitation is MAXNUMDEVS.  If more devices are supported
    // than that, limit it to the first MAXNUMDEVS.
    //

    if( cDevices > MAXNUMDEVS ) {
        cDevices = MAXNUMDEVS;
    }

    for( Device = 0; Device < cDevices; Device++ ) {

        DWORD TranslatedDeviceNumber;

        TranslatedDeviceNumber =
                  wdmaudTranslateDeviceNumber(pWdmaContext,
                                              MixerDevice,
                                              DeviceInterface,
                                              Device);

        if(TranslatedDeviceNumber == MAXULONG) {
             continue;
        }

        pmxd = &pWdmaContext->MixerDevs[ TranslatedDeviceNumber ];

        //
        // Open SysAudio
        //
        DPFASSERT(pmxd->pfo == NULL);

        pmxd->pfo = kmxlOpenSysAudio();
        if( pmxd->pfo == NULL ) {
            DPF(DL_WARNING|FA_USER,( "failed to open SYSAUDIO!" ) );
            RETURN( STATUS_UNSUCCESSFUL );
        }
        //
        // Set the current device instance in SysAudio.
        //

        Status = SetSysAudioProperty(
            pmxd->pfo,
            KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE,
            sizeof( pmxd->Device ),
            &pmxd->Device
            );
        if( !NT_SUCCESS( Status ) ) {
            DPF(DL_WARNING|FA_USER, ( "failed to set SYSAUDIO device instance" ) );
//            DPF(DL_ERROR|FA_ALL,("If fo is NULL, we must exit here!") );
            kmxlCloseSysAudio( pmxd->pfo );
            pmxd->pfo=NULL;
            Error = TRUE;
        } else {

            //
            // Initialize the topology for this device
            //

            Status = kmxlInit( pmxd->pfo, pmxd );
            if( !NT_SUCCESS( Status ) ) {
                DPF(DL_WARNING|FA_USER, ( "failed to initialize topology for device %d (%x)!",
                                  TranslatedDeviceNumber, Status ) );
                Error = TRUE;
            } else {

                //
                // Here we want to optimize out the restoring of values on the mixer
                // device.  If we find that there is another mixer device in some
                // other open context, then we will NOT call kmxlRetrieveAll to
                // set the values on the device.
                //
                DPF(DL_TRACE|FA_USER,( "Looking for Mixer: %S",pmxd->DeviceInterface ) );

                if( !NT_SUCCESS(EnumFsContext( HasMixerBeenInitialized, pmxd, pWdmaContext )) )
                {
                    //
                    // Here we find that this device was not found, thus this is
                    // the first time through.  Set the defaults here.
                    //
                    DPF(DL_TRACE|FA_USER,( "Did not find Mixer - initializing: %S",pmxd->DeviceInterface ) );

                    kmxlRetrieveAll( pmxd->pfo, pmxd );
                } else {
                    DPF(DL_TRACE|FA_USER,( "Found Mixer: %S",pmxd->DeviceInterface ) );
                }
            }
        }
    }

    if( Error ) {
        RETURN( STATUS_UNSUCCESSFUL );
    } else {
        return( STATUS_SUCCESS );
    }
}

//
// This routine looks in the WDMACONTEXT structure to see if this mixer device
// has already been initialized.  It does this by walking the MixerDevice list and
// checking to see if there are any devices that match this mixer devices's
// DeviceInterface string.  If it finds that there is a match, it routines 
// STATUS_SUCCESS, else it returns STATUS_MORE_ENTRIES so that the enum function
// will call it again until the list is empty.
//
NTSTATUS
HasMixerBeenInitialized(
    PWDMACONTEXT pContext,
    PVOID pvoidRefData,
    PVOID pvoidRefData2
    )
{
    NTSTATUS     Status;
    PMIXERDEVICE pmxdMatch;
    PMIXERDEVICE pmxd;
    DWORD        TranslatedDeviceNumber;
    ULONG        Device;
    PWDMACONTEXT pCurContext;

    //
    // Default is that we did not find this entry in the list.
    //
    Status = STATUS_MORE_ENTRIES;
    //
    // The reference data is a PMIXERDEVICE.
    //
    pmxdMatch = (PMIXERDEVICE)pvoidRefData;
    pCurContext = (PWDMACONTEXT)pvoidRefData2;

    if( pCurContext != pContext )
    {
        for( Device = 0; Device < MAXNUMDEVS; Device++ ) 
        {
            //
            // If this mixer device translates, that means that it can
            // be found in this context.
            //
            TranslatedDeviceNumber =
                      wdmaudTranslateDeviceNumber(pContext,
                                                  MixerDevice,
                                                  pmxdMatch->DeviceInterface,
                                                  Device);

            //
            // If it doesn't, we'll keep looking.
            //
            if( MAXULONG != TranslatedDeviceNumber ) 
            {
                DPF(DL_TRACE|FA_USER,( "Found Mixer: %S",pmxdMatch->DeviceInterface ) );

                Status = STATUS_SUCCESS;
                break;
            }
        }
    } else {
        DPF(DL_TRACE|FA_USER,( "Same context: %x",pCurContext ) );
    }
    return Status;
}

///////////////////////////////////////////////////////////////////////
//
// kmxlOpenHandler
//
// Handles the MXDM_OPEN message.  Copies the callback info from the
// caller and opens an instance of SysAudio set to the device number
// the caller has selected.
//
//

NTSTATUS
kmxlOpenHandler(
    IN PWDMACONTEXT pWdmaContext,
    IN LPDEVICEINFO DeviceInfo,      // Info structure
    IN LPVOID       DataBuffer       // Unused
)
{
    NTSTATUS       Status = STATUS_SUCCESS;
    PMIXERDEVICE   pmxd;

    PAGED_CODE();

    ASSERT( DeviceInfo );
    //
    // BUGBUG: we should not need this any more!
    //
    ASSERT( DeviceInfo->dwInstance == 0 );

    pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
    if( pmxd == NULL ) {
        goto exit;
    }
    DPF(DL_TRACE|FA_INSTANCE,( "param=( %d ) = pmxd = %X",
              DeviceInfo->DeviceNumber,pmxd));

    ExAcquireFastMutex( &ReferenceCountMutex );

    ++ReferenceCount;

    ExReleaseFastMutex( &ReferenceCountMutex );

    DeviceInfo->mmr = MMSYSERR_NOERROR;

exit:
    return( STATUS_SUCCESS );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlCloseHandler
//
// Handles the MXDM_CLOSE message.  Clears the callback info and
// closes the handle to SysAudio.
//
//

NTSTATUS
kmxlCloseHandler(
    IN LPDEVICEINFO DeviceInfo,         // Info structure
    IN LPVOID       DataBuffer          // Unused
)
{
    PAGED_CODE();
    ASSERT( DeviceInfo );
    ASSERT( DeviceInfo->dwInstance );

    DPF(DL_TRACE|FA_INSTANCE,( "kmxlCloseHandler"));
    
    ExAcquireFastMutex( &ReferenceCountMutex );

    --ReferenceCount;

    ExReleaseFastMutex( &ReferenceCountMutex );

    DeviceInfo->mmr = MMSYSERR_NOERROR;
    return( STATUS_SUCCESS );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlGetLineInfoHandler
//
// Handles the MXDM_GETLINEINFO message.  Determines which query
// is requested by looking at dwFlags and performs that query.
//
//

NTSTATUS
kmxlGetLineInfoHandler(
    IN PWDMACONTEXT pWdmaContext,
    IN LPDEVICEINFO DeviceInfo,         // Device Info structure
    IN LPVOID       DataBuffer          // MIXERLINE(16) to fill
)
{
    MIXERLINE ml;

    PAGED_CODE();
    ASSERT( DeviceInfo );

    if( DataBuffer == NULL ) {
        DPF(DL_WARNING|FA_USER,( "DataBuffer is NULL" ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    ml.cbStruct = sizeof( MIXERLINE );

    switch( DeviceInfo->dwFlags & MIXER_GETLINEINFOF_QUERYMASK ) {

        ///////////////////////////////////////////////////////////////
        case MIXER_GETLINEINFOF_COMPONENTTYPE:
        ///////////////////////////////////////////////////////////////
        // Valid fields:                                             //
        //   cbStruct                                                //
        //   dwComponentType                                         //
        ///////////////////////////////////////////////////////////////

            NOT16( DeviceInfo );
            ml.cbStruct        = sizeof( MIXERLINE );
            ml.dwComponentType = ( (LPMIXERLINE) DataBuffer) ->dwComponentType;

            DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoByComponent( %s )",
                    ComponentTypeToString( ml.dwComponentType ) ));

            return( kmxlGetLineInfoByComponent( pWdmaContext,
                                                DeviceInfo,
                                                DataBuffer,
                                                ml.dwComponentType
                                              )
                  );

        ///////////////////////////////////////////////////////////////
        case MIXER_GETLINEINFOF_DESTINATION:
        ///////////////////////////////////////////////////////////////
        // Valid fields:                                             //
        //   cbStruct                                                //
        //   dwDestination                                           //
        ///////////////////////////////////////////////////////////////

            NOT16( DeviceInfo );
            ml.dwDestination = ( (LPMIXERLINE) DataBuffer)->dwDestination;
            DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoById( S=%08X, D=%08X )",
                       -1, ml.dwDestination ));

            return( kmxlGetLineInfoByID( pWdmaContext,
                                         DeviceInfo,
                                         DataBuffer,
                                         (WORD) -1,
                                         (WORD) ml.dwDestination ) );

        ///////////////////////////////////////////////////////////////
        case MIXER_GETLINEINFOF_LINEID:
        ///////////////////////////////////////////////////////////////
        // Valid fields:                                             //
        //   cbStruct                                                //
        //   dwLineID                                                //
        ///////////////////////////////////////////////////////////////

            NOT16( DeviceInfo );
            ml.dwLineID = ( (LPMIXERLINE) DataBuffer)->dwLineID;

            DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoById( S=%08X, D=%08X )",
                       HIWORD( ml.dwLineID ), LOWORD( ml.dwLineID ) ));

            return( kmxlGetLineInfoByID( pWdmaContext,
                                         DeviceInfo,
                                         DataBuffer,
                                         HIWORD( ml.dwLineID ),
                                         LOWORD( ml.dwLineID ) ) );

        ///////////////////////////////////////////////////////////////
        case MIXER_GETLINEINFOF_SOURCE:
        ///////////////////////////////////////////////////////////////
        // Valid fields:                                             //
        //   cbStruct                                                //
        //   dwSource                                                //
        //   dwDestination                                           //
        ///////////////////////////////////////////////////////////////

            NOT16( DeviceInfo );
            ml.dwSource      = ( (LPMIXERLINE) DataBuffer)->dwSource;
            ml.dwDestination = ( (LPMIXERLINE) DataBuffer)->dwDestination;

            DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoById( S=%08X, D=%08X )",
                       ml.dwSource, ml.dwDestination ));

            return( kmxlGetLineInfoByID( pWdmaContext,
                                         DeviceInfo,
                                         DataBuffer,
                                         (WORD) ml.dwSource,
                                         (WORD) ml.dwDestination ) );

        ///////////////////////////////////////////////////////////////
        case MIXER_GETLINEINFOF_TARGETTYPE:
        ///////////////////////////////////////////////////////////////
        // Valid fields:                                             //
        //   cbStruct                                                //
        //   Target.dwType                                           //
        //   Target.wMid                                             //
        //   Target.wPid                                             //
        //   Target.vDriverVersion                                   //
        //   Target.szPname                                          //
        ///////////////////////////////////////////////////////////////

            NOT16( DeviceInfo );
            ml.Target.dwType         = ((LPMIXERLINE) DataBuffer)->Target.dwType;

            DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoByType( %x -- %s )",
                       ml.Target.dwType,
                       TargetTypeToString( ml.Target.dwType ) ));

            return( kmxlGetLineInfoByType( pWdmaContext,
                                           DeviceInfo,
                                           DataBuffer,
                                           ml.Target.dwType ) );

        ///////////////////////////////////////////////////////////////
        default:
        ///////////////////////////////////////////////////////////////

            DPF(DL_WARNING|FA_USER,( "invalid flags ( %x )", DeviceInfo->dwFlags ));
            DeviceInfo->mmr = MMSYSERR_INVALPARAM;
            return( STATUS_SUCCESS );
    }

    DPF(DL_WARNING|FA_USER,("Unmatched di->dwFlag") );
    DeviceInfo->mmr = MMSYSERR_INVALPARAM;
    return( STATUS_SUCCESS );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlGetLineControlsHandler
//
// Handles the MXDM_GETLINECONTROLS message.  Determines the query
// requested and finds the controls.
//
//

NTSTATUS
kmxlGetLineControlsHandler(
    IN PWDMACONTEXT pWdmaContext,
    IN LPDEVICEINFO DeviceInfo,         // Device Info structure
    IN LPVOID       DataBuffer,         // MIXERLINECONTROLS(16) to fill
    IN LPVOID       pamxctrl
)
{
    PMIXERDEVICE   pmxd;
    PMXLLINE       pLine;
    PMXLCONTROL    pControl;
    ULONG          Count;
    DWORD          dwLineID,
                   dwControlID,
                   dwControlType,
                   cControls,
                   cbmxctrl;

    PAGED_CODE();
    ASSERT( DeviceInfo );

    //
    // Check some pre-conditions so we don't blow up later.
    //

    if( DataBuffer == NULL ) {
        DPF(DL_WARNING|FA_USER,( "DataBuffer is NULL!" ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    if( pamxctrl == NULL ) {
        DPF(DL_WARNING|FA_USER,( "pamxctrl is NULL!" ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    if( DeviceInfo->DeviceNumber > MAXNUMDEVS ) {
        DPF(DL_WARNING|FA_USER,( "device Id is invalid!" ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    //
    // Get a instance reference
    //

    pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
    if( pmxd == NULL ) {
        return( STATUS_SUCCESS );
    }

    //
    // Copy out some parameters necessary to find the controls
    //

    NOT16( DeviceInfo );
    dwLineID      = ((LPMIXERLINECONTROLS) DataBuffer)->dwLineID;
    dwControlID   = ((LPMIXERLINECONTROLS) DataBuffer)->dwControlID;
    dwControlType = ((LPMIXERLINECONTROLS) DataBuffer)->dwControlType;
    cControls     = ((LPMIXERLINECONTROLS) DataBuffer)->cControls;
    cbmxctrl      = ((LPMIXERLINECONTROLS) DataBuffer)->cbmxctrl;

    switch( DeviceInfo->dwFlags & MIXER_GETLINECONTROLSF_QUERYMASK ) {

        ///////////////////////////////////////////////////////////////
        case MIXER_GETLINECONTROLSF_ALL:
        ///////////////////////////////////////////////////////////////

            //
            // Find the line that matches the dwLineID field
            //

            DPF(DL_TRACE|FA_USER,( "kmxlGetLineControls( ALL, %08X )",dwLineID ));

            pLine = kmxlFindLine( pmxd, dwLineID );
            if( pLine == NULL ) {
                DPF(DL_WARNING|FA_USER,( "ALL - invalid line Id %x!",dwLineID ));
                DeviceInfo->mmr = MIXERR_INVALLINE;
                return( STATUS_SUCCESS );
            }

            //
            // Loop through the controls, copying them into the user buffer.
            //

            Count = 0;
            pControl = kmxlFirstInList( pLine->Controls );
            while( pControl && Count < cControls ) {

                NOT16( DeviceInfo );
                RtlCopyMemory(
                    &((LPMIXERCONTROL) pamxctrl)[ Count ],
                    &pControl->Control,
                    min(cbmxctrl,sizeof(MIXERCONTROL)) );

                pControl = kmxlNextControl( pControl );
                ++Count;
            }

            DeviceInfo->mmr = MMSYSERR_NOERROR;
            return( STATUS_SUCCESS );

        ///////////////////////////////////////////////////////////////
        case MIXER_GETLINECONTROLSF_ONEBYID:
        ///////////////////////////////////////////////////////////////

            pControl = kmxlFindControl( pmxd, dwControlID );
            pLine = kmxlFindLineForControl(
                    pControl,
                    pmxd->listLines
                    );
            if( pLine == NULL ) {
                DPF(DL_WARNING|FA_USER,( "ONEBYID - invalid control Id %x!", dwControlID ));
                DeviceInfo->mmr = MIXERR_INVALCONTROL;
                return( STATUS_SUCCESS );
            }

            DPF(DL_TRACE|FA_USER,( "kmxlGetLineControls( ONEBYID, Ctrl=%08X, Line=%08X )",
                       dwControlID, pLine->Line.dwLineID ));

            if( pControl ) {

                NOT16( DeviceInfo );
                RtlCopyMemory((LPMIXERLINECONTROLS) pamxctrl,
                              &pControl->Control,
                              min(cbmxctrl,sizeof(MIXERCONTROL)) );

                ((PMIXERLINECONTROLS) DataBuffer)->dwLineID =
                    (DWORD) pLine->Line.dwLineID;

                DeviceInfo->mmr = MMSYSERR_NOERROR;
                return( STATUS_SUCCESS );

            } else {
                DPF(DL_WARNING|FA_USER,( "ONEBYID - invalid dwControlID %08X!", dwControlID ));
                DeviceInfo->mmr = MIXERR_INVALCONTROL;
                return( STATUS_SUCCESS );
            }

        ///////////////////////////////////////////////////////////////
        case MIXER_GETLINECONTROLSF_ONEBYTYPE:
        ///////////////////////////////////////////////////////////////

            //
            // Find the line that matches the dwLineID field
            //

            pLine = kmxlFindLine( pmxd, dwLineID );
            if( pLine == NULL ) {
                DPF(DL_WARNING|FA_USER,( "ONEBYTYPE - invalid dwLineID %08X!", dwControlType ));
                DeviceInfo->mmr = MIXERR_INVALLINE;
                return( STATUS_SUCCESS );
            }

            DPF(DL_TRACE|FA_USER, ("kmxlGetLineControls( ONEBYTYPE, Type=%s, Line=%08X )",
                    ControlTypeToString( dwControlType ),
                    pLine->Line.dwLineID ));

            //
            // Now look through the controls and find the control that
            // matches the type the caller has passed.
            //

            pControl = kmxlFirstInList( pLine->Controls );
            while( pControl ) {

                if( pControl->Control.dwControlType == dwControlType )
                {

                    NOT16 ( DeviceInfo );
                    RtlCopyMemory((LPMIXERCONTROL) pamxctrl,
                                  &pControl->Control,
                                  min(cbmxctrl,sizeof(MIXERCONTROL)) );
                    DeviceInfo->mmr = MMSYSERR_NOERROR;
                    return( STATUS_SUCCESS );
                }

                pControl = kmxlNextControl( pControl );
            }

            DPF(DL_WARNING|FA_USER,( "(ONEBYTYPE,Type=%x,Line=%08X ) no such control type on line",
                             dwControlType, pLine->Line.dwLineID ));
            DeviceInfo->mmr = MIXERR_INVALCONTROL;
            return( STATUS_SUCCESS );

        ///////////////////////////////////////////////////////////////
        default:
        ///////////////////////////////////////////////////////////////

            DPF(DL_WARNING|FA_USER,( "invalid flags %x",DeviceInfo->dwFlags ));
            DeviceInfo->mmr = MMSYSERR_INVALPARAM;
            return( STATUS_SUCCESS );

    }
}

///////////////////////////////////////////////////////////////////////
//
// kmxlGetControlDetailsHandler
//
// Determines which control is being queried and calls the appropriate
// handler to perform the get property.
//
//

NTSTATUS
kmxlGetControlDetailsHandler(
    IN PWDMACONTEXT pWdmaContext,
    IN LPDEVICEINFO DeviceInfo,         // Device Info Structure
    IN LPVOID       DataBuffer,         // MIXERCONTROLDETAILS structure
    IN LPVOID       paDetails           // Flat pointer to details struct(s)
)
{
    LPMIXERCONTROLDETAILS pmcd     = (LPMIXERCONTROLDETAILS) DataBuffer;
    PMXLCONTROL           pControl;
    PMIXERDEVICE          pmxd;
    NTSTATUS              Status;
    PMXLLINE              pLine;

    PAGED_CODE();
    ASSERT( DeviceInfo );

    pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
    if( pmxd == NULL ) {
        return( STATUS_SUCCESS );
    }

    pControl = kmxlFindControl( pmxd, pmcd->dwControlID );
    if( pControl == NULL ) {
        DPF(DL_WARNING|FA_USER,( "control %x not found",pmcd->dwControlID ));
        DeviceInfo->mmr = MIXERR_INVALCONTROL;
        return( STATUS_SUCCESS );
    }

    pLine = kmxlFindLineForControl(
        pControl,
        pmxd->listLines
        );
    if( pLine == NULL ) {
        DPF(DL_WARNING|FA_USER,( "invalid control id %x!",pmcd->dwControlID ));
        DeviceInfo->mmr = MIXERR_INVALCONTROL;
        return( STATUS_SUCCESS );
    }

    if( ( pControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) &&
        ( pmcd->cChannels != 1 ) &&
        ( pControl->Control.dwControlType != MIXERCONTROL_CONTROLTYPE_MUX )) {
        DPF(DL_WARNING|FA_USER,( "incorrect cChannels ( %d ) on UNIFORM control %x!",
            pmcd->cChannels, pmcd->dwControlID  ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    if( pmcd->cChannels > pLine->Line.cChannels ) {
        DPF(DL_WARNING|FA_USER,( "incorrect number of channels( %d )!",pmcd->cChannels ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    if( pmcd->cMultipleItems != pControl->Control.cMultipleItems ) {
        DPF(DL_WARNING|FA_USER,( "incorrect number of items( %d )!",pmcd->cMultipleItems ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    switch( DeviceInfo->dwFlags & MIXER_GETCONTROLDETAILSF_QUERYMASK ) {

        ///////////////////////////////////////////////////////////////
        case MIXER_GETCONTROLDETAILSF_LISTTEXT:
        ///////////////////////////////////////////////////////////////

        {
            ULONG cMultipleItems;
            LPMIXERCONTROLDETAILS_LISTTEXT lplt;

            DPF(DL_TRACE|FA_USER,( "kmxlGetControlDetails( Ctrl=%d )",
                       pControl->Control.dwControlID ));

            NOT16( DeviceInfo );

            lplt = (LPMIXERCONTROLDETAILS_LISTTEXT) paDetails;
            for( cMultipleItems = 0;
                 cMultipleItems < pmcd->cMultipleItems;
                 cMultipleItems++ )
            {
                RtlCopyMemory(
                    &lplt[ cMultipleItems ],
                    &pControl->Parameters.lpmcd_lt[ cMultipleItems ],
                    sizeof( MIXERCONTROLDETAILS_LISTTEXT )
                    );
            }
        }

            DeviceInfo->mmr = MMSYSERR_NOERROR;
            break;

        ///////////////////////////////////////////////////////////////
        case MIXER_GETCONTROLDETAILSF_VALUE:
        ///////////////////////////////////////////////////////////////

            switch( pControl->Control.dwControlType ) {

                ///////////////////////////////////////////////////////
                case MIXERCONTROL_CONTROLTYPE_MIXER:
                ///////////////////////////////////////////////////////

                    DeviceInfo->mmr = MMSYSERR_NOTSUPPORTED;
                    DPF(DL_WARNING|FA_USER,( "mixers are not supported" ));
                    break;

                ///////////////////////////////////////////////////////
                case MIXERCONTROL_CONTROLTYPE_PEAKMETER:
                ///////////////////////////////////////////////////////

                    Status = kmxlHandleGetUnsigned(
                        DeviceInfo,
                        pmxd,
                        pControl,
                        pControl->PropertyId,
                        (LPMIXERCONTROLDETAILS) DataBuffer,
                        (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                        MIXER_FLAG_SCALE
                        );
                    break;

                ///////////////////////////////////////////////////////
                case MIXERCONTROL_CONTROLTYPE_MUTE:
                ///////////////////////////////////////////////////////

                    if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_MUTE ) ) {
                        Status = kmxlHandleGetUnsigned(
                            DeviceInfo,
                            pmxd,
                            pControl,
                            KSPROPERTY_AUDIO_MUTE,
                            (LPMIXERCONTROLDETAILS) DataBuffer,
                            (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                            0
                            );
                    } else if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
                        Status = kmxlHandleGetMuteFromSuperMix(
                            DeviceInfo,
                            pmxd,
                            pControl,
                            (LPMIXERCONTROLDETAILS) DataBuffer,
                            (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                            0
                            );
                    } else {
                        DPF(DL_WARNING|FA_USER,("Unmatched GUID") );
                    }
                    break;

                ///////////////////////////////////////////////////////
                case MIXERCONTROL_CONTROLTYPE_VOLUME:
                //////////////////////////////////////////////////////

                    #ifdef SUPERMIX_AS_VOL
                    if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_VOLUME ) ) {
                    #endif
                        Status = kmxlHandleGetUnsigned(
                            DeviceInfo,
                            pmxd,
                            pControl,
                            pControl->PropertyId,
                            (LPMIXERCONTROLDETAILS) DataBuffer,
                            (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                            MIXER_FLAG_SCALE
                            );
                    #ifdef SUPERMIX_AS_VOL
                    } else if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
                        Status = kmxlHandleGetVolumeFromSuperMix(
                            DeviceInfo,
                            pmxd,
                            pControl,
                            (LPMIXERCONTROLDETAILS) DataBuffer,
                            (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                            MIXER_FLAG_SCALE
                            );

                    } else {
                        DPF(DL_WARNING|FA_USER,("Invalid GUID for Control.") );
                    }
                    #endif // SUPERMIX_AS_VOL
                    break;

                ///////////////////////////////////////////////////////
                case MIXERCONTROL_CONTROLTYPE_TREBLE:
                case MIXERCONTROL_CONTROLTYPE_BASS:
                ///////////////////////////////////////////////////////
                // These all take 32-bit parameters per channel but  //
                // need to be scale from dB to linear                //
                ///////////////////////////////////////////////////////

                    Status = kmxlHandleGetUnsigned(
                        DeviceInfo,
                        pmxd,
                        pControl,
                        pControl->PropertyId,
                        (LPMIXERCONTROLDETAILS) DataBuffer,
                        (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                        MIXER_FLAG_SCALE
                        );
                    break;

                ///////////////////////////////////////////////////////
                case MIXERCONTROL_CONTROLTYPE_LOUDNESS:
                case MIXERCONTROL_CONTROLTYPE_ONOFF:
                case MIXERCONTROL_CONTROLTYPE_BOOLEAN:
                case MIXERCONTROL_CONTROLTYPE_MUX:
                case MIXERCONTROL_CONTROLTYPE_FADER:
                case MIXERCONTROL_CONTROLTYPE_BASS_BOOST:
                ///////////////////////////////////////////////////////
                // These all take up to 32-bit parameters per channel//
                ///////////////////////////////////////////////////////

                    Status = kmxlHandleGetUnsigned(
                        DeviceInfo,
                        pmxd,
                        pControl,
                        pControl->PropertyId,
                        (LPMIXERCONTROLDETAILS) DataBuffer,
                        (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                        0
                        );
                    break;

                ///////////////////////////////////////////////////////
                default:
                ///////////////////////////////////////////////////////

                    DeviceInfo->mmr = MMSYSERR_INVALPARAM;
                    break;
            }
            break;

        ///////////////////////////////////////////////////////////////
        default:
        ///////////////////////////////////////////////////////////////

            DeviceInfo->mmr = MMSYSERR_NOTSUPPORTED;
            break;
    }

    return( STATUS_SUCCESS );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlSetControlDetailsHandler
//
// Determines which control is being set and calls the appropriate
// handler to perform the set property.
//
//

NTSTATUS
kmxlSetControlDetailsHandler(
    IN PWDMACONTEXT pWdmaContext,
    IN OUT LPDEVICEINFO DeviceInfo,         // Device Info structure
    IN LPVOID       DataBuffer,         // MIXERCONTROLDETAILS structure
    IN LPVOID       paDetails,          // Flat pointer to detail struct(s)
    IN ULONG        Flags
)
{
    LPMIXERCONTROLDETAILS pmcd     = (LPMIXERCONTROLDETAILS) DataBuffer;
    PMXLCONTROL           pControl;
    NTSTATUS              Status;
    PMIXERDEVICE          pmxd;
    PMXLLINE              pLine;

    PAGED_CODE();
    ASSERT( DeviceInfo );

    //
    // Get a instance reference
    //

    pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
    if( pmxd == NULL ) {
        return( STATUS_SUCCESS );
    }

    pControl = kmxlFindControl( pmxd, pmcd->dwControlID );
    if( pControl == NULL ) {
        DPF(DL_WARNING|FA_USER,( "control %d not found",pmcd->dwControlID ));
        DeviceInfo->mmr = MIXERR_INVALCONTROL;
        return( STATUS_SUCCESS );
    }

    pLine = kmxlFindLineForControl(
        pControl,
        pmxd->listLines
        );
    if( pLine == NULL ) {
        DPF(DL_WARNING|FA_USER,( "invalid control id %d",pControl->Control.dwControlID ));
        DeviceInfo->mmr = MIXERR_INVALCONTROL;
        return( STATUS_SUCCESS );
    }

    if( ( pControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) &&
        ( pmcd->cChannels != 1 ) &&
        ( pControl->Control.dwControlType != MIXERCONTROL_CONTROLTYPE_MUX )) {
        DPF(DL_WARNING|FA_USER,( "incorrect cChannels ( %d ) on UNIFORM control %d",
                         pmcd->cChannels,
                         pControl->Control.dwControlID ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    if( pmcd->cChannels > pLine->Line.cChannels ) {
        DPF(DL_WARNING|FA_USER,( "incorrect number of channels ( %d ) on line %08x",
                         pmcd->cChannels,
                         pLine->Line.dwLineID ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    if( pmcd->cMultipleItems != pControl->Control.cMultipleItems ) {
        DPF(DL_WARNING|FA_USER,( "incorrect number of items ( %d ) on control %d ( %d )",
                         pmcd->cMultipleItems,
                         pControl->Control.dwControlID,
                         pControl->Control.cMultipleItems ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    switch( DeviceInfo->dwFlags & MIXER_SETCONTROLDETAILSF_QUERYMASK ) {

        ///////////////////////////////////////////////////////////////
        case MIXER_SETCONTROLDETAILSF_VALUE:
        ///////////////////////////////////////////////////////////////

            switch( pControl->Control.dwControlType ) {

                ///////////////////////////////////////////////////////
                case MIXERCONTROL_CONTROLTYPE_MIXER:
                ///////////////////////////////////////////////////////

                    DeviceInfo->mmr = MMSYSERR_NOTSUPPORTED;
                    DPF(DL_WARNING|FA_USER,( "mixers are not supported" ));
                    break;

                ///////////////////////////////////////////////////////
                case MIXERCONTROL_CONTROLTYPE_PEAKMETER:
                ///////////////////////////////////////////////////////

                    Status = kmxlHandleSetUnsigned(
                        DeviceInfo,
                        pmxd,
                        pControl,
                        pControl->PropertyId,
                        (LPMIXERCONTROLDETAILS) DataBuffer,
                        (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                        Flags | MIXER_FLAG_SCALE
                        );
                    break;

                ///////////////////////////////////////////////////////
                case MIXERCONTROL_CONTROLTYPE_MUTE:
                ///////////////////////////////////////////////////////

                    if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_MUTE ) ) {
                        Status = kmxlHandleSetUnsigned(
                            DeviceInfo,
                            pmxd,
                            pControl,
                            KSPROPERTY_AUDIO_MUTE,
                            (LPMIXERCONTROLDETAILS) DataBuffer,
                            (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                            Flags
                            );
                    } else if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
                        Status = kmxlHandleSetMuteFromSuperMix(
                            DeviceInfo,
                            pmxd,
                            pControl,
                            (LPMIXERCONTROLDETAILS) DataBuffer,
                            (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                            Flags
                            );
                    } else {
                        DPF(DL_WARNING|FA_USER,("Invalid GUID for Control Type Mute.") );
                    }

                    kmxlNotifyLineChange(
                        DeviceInfo,
                        pmxd,
                        pLine,
                        (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails
                        );
                    break;

                ///////////////////////////////////////////////////////
                case MIXERCONTROL_CONTROLTYPE_VOLUME:
                ///////////////////////////////////////////////////////

                    #ifdef SUPERMIX_AS_VOL
                    if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_VOLUME ) ) {
                    #endif // SUPERMIX_AS_VOL
                        Status = kmxlHandleSetUnsigned(
                            DeviceInfo,
                            pmxd,
                            pControl,
                            pControl->PropertyId,
                            (LPMIXERCONTROLDETAILS) DataBuffer,
                            (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                            Flags | MIXER_FLAG_SCALE
                            );
                    #ifdef SUPERMIX_AS_VOL
                    } else if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
                        Status = kmxlHandleSetVolumeFromSuperMix(
                            DeviceInfo,
                            pmxd,
                            pControl,
                            (LPMIXERCONTROLDETAILS) DataBuffer,
                            (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                            Flags | MIXER_FLAG_SCALE
                            );
                    } else {
                        DPF(DL_WARNING|FA_USER,("Invalid GUID for Control Type Volume.") );
                    }
                    #endif
                    break;

                ///////////////////////////////////////////////////////
                case MIXERCONTROL_CONTROLTYPE_TREBLE:
                case MIXERCONTROL_CONTROLTYPE_BASS:
                ///////////////////////////////////////////////////////
                // These all take 32-bit parameters per channel but  //
                // need to be scale from linear to dB                //
                ///////////////////////////////////////////////////////

                    Status = kmxlHandleSetUnsigned(
                        DeviceInfo,
                        pmxd,
                        pControl,
                        pControl->PropertyId,
                        (LPMIXERCONTROLDETAILS) DataBuffer,
                        (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                        Flags | MIXER_FLAG_SCALE
                        );
                     break;

                ///////////////////////////////////////////////////////
                case MIXERCONTROL_CONTROLTYPE_LOUDNESS:
                case MIXERCONTROL_CONTROLTYPE_ONOFF:
                case MIXERCONTROL_CONTROLTYPE_BOOLEAN:
                case MIXERCONTROL_CONTROLTYPE_MUX:
                case MIXERCONTROL_CONTROLTYPE_FADER:
                case MIXERCONTROL_CONTROLTYPE_BASS_BOOST:
                ///////////////////////////////////////////////////////
                // These all take up to 32-bit parameters per channel//
                ///////////////////////////////////////////////////////

                    Status = kmxlHandleSetUnsigned(
                        DeviceInfo,
                        pmxd,
                        pControl,
                        pControl->PropertyId,
                        (LPMIXERCONTROLDETAILS) DataBuffer,
                        (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
                        Flags
                        );
                    break;

                ///////////////////////////////////////////////////////
                default:
                ///////////////////////////////////////////////////////

                    DeviceInfo->mmr = MMSYSERR_INVALPARAM;
                    break;
            }
            break;

        ///////////////////////////////////////////////////////////////
        default:
        ///////////////////////////////////////////////////////////////

            DPF(DL_WARNING|FA_USER,( "invalid flags %x",DeviceInfo->dwFlags ));
            DeviceInfo->mmr = MMSYSERR_NOTSUPPORTED;
            break;
    }

    return( STATUS_SUCCESS );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlFindControl
//
//

PMXLCONTROL
kmxlFindControl(
    IN PMIXERDEVICE pmxd,             // The mixer instance to search
    IN DWORD        dwControlID       // The control ID to find
)
{
    PMXLLINE    pLine;
    PMXLCONTROL pControl;

    PAGED_CODE();
    pLine = kmxlFirstInList( pmxd->listLines );
    while( pLine ) {

        pControl = kmxlFirstInList( pLine->Controls );
        while( pControl ) {
            if( pControl->Control.dwControlID == dwControlID ) {
                return( pControl );
            }
            pControl = kmxlNextControl( pControl );
        }

        pLine = kmxlNextLine( pLine );
    }

    return( NULL );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlFindLine
//
// For the given line ID, kmxlFindLine will find the matching
// MXLLINE structure for it.
//
//

PMXLLINE
kmxlFindLine(
    IN PMIXERDEVICE   pmxd,
    IN DWORD          dwLineID          // The line ID to find
)
{
    PMXLLINE pLine;

    PAGED_CODE();
    pLine = kmxlFirstInList( pmxd->listLines );
    while( pLine ) {

        if( pLine->Line.dwLineID == dwLineID ) {
            return( pLine );
        }

        pLine = kmxlNextLine( pLine );
    }

    return( NULL );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlGetLineInfoByID
//
// Loops through the lines looking for a line that has a matching
// source and destination Id.
//
//

NTSTATUS
kmxlGetLineInfoByID(
    IN PWDMACONTEXT pWdmaContext,
    IN LPDEVICEINFO DeviceInfo,         // Device Info structure
    IN LPVOID       DataBuffer,         // MIXERLINE(16) structure
    IN WORD         Source,             // Source line id
    IN WORD         Destination         // Destination line id
)
{
    PMIXERDEVICE   pmxd;
    PMXLLINE       pLine;
    BOOL           bDestination;

    PAGED_CODE();

    ASSERT( DeviceInfo );
    ASSERT( DataBuffer );

    if( DeviceInfo->DeviceNumber > MAXNUMDEVS ) {
        DPF(DL_WARNING|FA_USER,( "invalid device number %d",DeviceInfo->DeviceNumber ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
    if( pmxd == NULL ) {
        return( STATUS_SUCCESS );
    }

    //
    // If the source is -1 (0xFFFF), then this line is a destination.
    //

    if( Source == (WORD) -1 ) {
        bDestination = TRUE;
        Source       = 0;
    } else {
        bDestination = FALSE;
    }

    pLine = kmxlFirstInList( pmxd->listLines );
    while( pLine ) {

        if( ( bDestination                                 &&
              ( pLine->Line.dwDestination == Destination ) &&
              ( pLine->Line.cConnections > 0             ) ) ||
            ( ( pLine->Line.dwSource      == Source )      &&
              ( pLine->Line.dwDestination == Destination ) ) )
        {

            NOT16( DeviceInfo );
            RtlCopyMemory((LPMIXERLINE) DataBuffer,
                          &pLine->Line,
                          sizeof( MIXERLINE ) );

            DeviceInfo->mmr = MMSYSERR_NOERROR;
            return( STATUS_SUCCESS );
        }
        pLine = kmxlNextLine( pLine );
    }

    //
    // There are no lines for the device number.
    //

    DPF(DL_WARNING|FA_USER,( "no matching lines for (S=%08X, D=%08X)",
                     Source,
                     Destination ));
    DeviceInfo->mmr = MMSYSERR_INVALPARAM;
    return( STATUS_SUCCESS );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlGetLineInfoByType
//
// Loops through all the lines looking for the first line that matches
// the Target type specified. Note that this will always only find the
// first one!
//
//

NTSTATUS
kmxlGetLineInfoByType(
    IN PWDMACONTEXT pWdmaContext,
    IN LPDEVICEINFO DeviceInfo,         // Device info structure
    IN LPVOID       DataBuffer,         // MIXERLINE(16) structure
    IN DWORD        dwType              // Line type to search for
)
{
    PMXLLINE       pLine;
    PMIXERDEVICE   pmxd;

    PAGED_CODE();
    ASSERT( DeviceInfo );
    ASSERT( DataBuffer );

    if( DeviceInfo->DeviceNumber > MAXNUMDEVS ) {
        DPF(DL_WARNING|FA_USER,( "invalid device id %x",DeviceInfo->DeviceNumber ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
    if( pmxd == NULL ) {
        return( STATUS_SUCCESS );
    }

    //
    // Loop through all the lines looking for a line that has the
    // specified target type.  Note that this will only return the
    // first one.
    //

    pLine = kmxlFirstInList( pmxd->listLines );
    while( pLine ) {

        if( pLine->Line.Target.dwType == dwType ) {

            LPMIXERLINE lpMxl = (LPMIXERLINE) DataBuffer;
            NOT16( DeviceInfo );

            if( lpMxl->Target.wMid != pLine->Line.Target.wMid ) {
                DeviceInfo->mmr = MMSYSERR_INVALPARAM;
                return( STATUS_SUCCESS );
            }

            if( lpMxl->Target.wPid != pLine->Line.Target.wPid ) {
                DeviceInfo->mmr = MMSYSERR_INVALPARAM;
                return( STATUS_SUCCESS );
            }

            if( wcscmp( pLine->Line.Target.szPname, lpMxl->Target.szPname ) )
            {
                DeviceInfo->mmr = MMSYSERR_INVALPARAM;
                return( STATUS_SUCCESS );
            }

            RtlCopyMemory((LPMIXERLINE) DataBuffer,
                          &pLine->Line,
                          sizeof( MIXERLINE ) );

            DeviceInfo->mmr = MMSYSERR_NOERROR;
            return( STATUS_SUCCESS );
        }
        pLine = kmxlNextLine( pLine );
    }

    //
    // The line was not found.  Return invalid parameter.
    //

    DPF(DL_WARNING|FA_USER,( "no matching line found for %x",dwType ));
    DeviceInfo->mmr = MMSYSERR_INVALPARAM;
    return( STATUS_SUCCESS );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlGetLineInfoByComponent
//
// Loops through the list of lines looking for a line that has a matching
// dwComponentType.  Note that this will always find only the first!
//
//

NTSTATUS
kmxlGetLineInfoByComponent(
    IN PWDMACONTEXT pWdmaContext,
    IN LPDEVICEINFO DeviceInfo,         // Device Info structure
    IN LPVOID       DataBuffer,         // MIXERLINE(16) structure
    IN DWORD        dwComponentType     // Component type to search for
)
{
    PMXLLINE       pLine;
    PMIXERDEVICE   pmxd;

    PAGED_CODE();
    ASSERT( DeviceInfo );
    ASSERT( DataBuffer );

    if( DeviceInfo->DeviceNumber > MAXNUMDEVS ) {
        DPF(DL_WARNING|FA_USER,( "invalid device id %x",DeviceInfo->DeviceNumber ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
    if( pmxd == NULL ) {
        return( STATUS_SUCCESS );
    }

    //
    // Loop through all the lines looking for a line that has a component
    // type matching what the user requested.
    //

    pLine = kmxlFirstInList( pmxd->listLines );
    while( pLine ) {

        if( pLine->Line.dwComponentType == dwComponentType ) {

            //
            // Copy the data into the user buffer
            //
            NOT16( DeviceInfo );
            RtlCopyMemory((LPMIXERLINE) DataBuffer,
                          &pLine->Line,
                          sizeof( MIXERLINE ) );

            DeviceInfo->mmr = MMSYSERR_NOERROR;
            return( STATUS_SUCCESS );
        }

        pLine = kmxlNextLine( pLine );
    }

    DPF(DL_WARNING|FA_USER,( "no matching line found for type %x",dwComponentType ));
    DeviceInfo->mmr = MMSYSERR_INVALPARAM;
    return( STATUS_SUCCESS );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlGetNumDestinations
//
// Returns the number of destinations stored in the mixer device
//
//

DWORD
kmxlGetNumDestinations(
    IN PMIXERDEVICE pMixerDevice        // The device
)
{
    PAGED_CODE();

    return( pMixerDevice->cDestinations );
}


///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//                                                                   //
//               I N S T A N C E   R O U T I N E S                   //
//                                                                   //
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
//
// kmxlReferenceInstance
//
// Determines if the dwInstance field of the DeviceInfo structure
// is valid.  If not, it creates a valid instance and sets a
// reference count of 1 on it.
//
//

LONG nextinstanceid=0;

DWORD kmxlUniqueInstanceId(VOID)
{
    PAGED_CODE();
    // Update our next valid instance id.  Do NOT allow zero.
    // Since that is used to signal that we want to allocate
    // a new instance.
    if (0==InterlockedIncrement(&nextinstanceid))
        InterlockedIncrement(&nextinstanceid);

    return nextinstanceid;
}



/////////////////////////////////////////////////////////////////////////////
//
// kmxlReferenceMixerDevice
//
// This routine Translates the device number and makes sure that there is a
// open SysAudio PFILE_OBJECT in this mixier device.  This will be the FILE_OBJECT
// that we use to talk to this mixer device.
//
// return:  PMIXERDEVICE on success NULL otherwise.
//
PMIXERDEVICE
kmxlReferenceMixerDevice(
    IN     PWDMACONTEXT pWdmaContext,
    IN OUT LPDEVICEINFO DeviceInfo      // Device Information
)
{
    NTSTATUS       Status;
    DWORD          TranslatedDeviceNumber;
    PMIXERDEVICE   pmxd;


    PAGED_CODE();
    DPFASSERT(IsValidDeviceInfo(DeviceInfo));


    TranslatedDeviceNumber =
              wdmaudTranslateDeviceNumber(pWdmaContext,
                                          DeviceInfo->DeviceType,
                                          DeviceInfo->wstrDeviceInterface,
                                          DeviceInfo->DeviceNumber);

    if( TranslatedDeviceNumber == MAXULONG ) {
        DPF(DL_WARNING|FA_INSTANCE,("Could not translate DeviceNumber! DT=%08X, DI=%08X, DN=%08X",
                                    DeviceInfo->DeviceType,
                                    DeviceInfo->wstrDeviceInterface,
                                    DeviceInfo->DeviceNumber) );
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( NULL );
    }

    pmxd = &pWdmaContext->MixerDevs[ TranslatedDeviceNumber ];

    if( pmxd->pfo == NULL )
    {
        DPF(DL_WARNING|FA_NOTE,("pmxd->pfo should have been set!") );
        //
        // This is the first time through this code.  Open SysAudio on this device
        // and set the mixer device.
        //
        // set the SysAudio file object
        if( NULL==(pmxd->pfo=kmxlOpenSysAudio())) {
            DPF(DL_WARNING|FA_INSTANCE,("OpenSysAudio failed") );
            DeviceInfo->mmr = MMSYSERR_INVALPARAM;
            return( NULL );
        }

        Status = SetSysAudioProperty(
            pmxd->pfo,
            KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE,
            sizeof( pmxd->Device ),
            &pmxd->Device
            );
        if( !NT_SUCCESS( Status ) ) {
            kmxlCloseSysAudio( pmxd->pfo );
            pmxd->pfo=NULL;
            DPF(DL_WARNING|FA_INSTANCE,("SetSysAudioProperty DEVICE_INSTANCE failed %X",Status) );
            DeviceInfo->mmr = MMSYSERR_INVALPARAM;
            return( NULL );
        }
    }
    //
    // BUGBUG:  we should not need this any more.
    //
    DeviceInfo->dwInstance=kmxlUniqueInstanceId();;

    return pmxd;
}



///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//                                                                   //
//           G E T / S E T  D E T A I L  H A N D L E R S             //
//                                                                   //
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
//
// kmxlIsSpeakerDestinationVolume
//
// Returns TRUE if the control is a volume control on the Speakers
// destination.
//
//

BOOL
kmxlIsSpeakerDestinationVolume(
     IN PMIXERDEVICE   pmxd,         // The mixer
     IN PMXLCONTROL    pControl      // The control to check
)
{
     PMXLLINE pLine;

     PAGED_CODE();
     DPFASSERT( IsValidMixerDevice(pmxd) );
     DPFASSERT( IsValidControl(pControl) );

     //
     // Find a line for this control.  If none is found, then this can't
     // be a destination volume.
     //

     pLine = kmxlFindLineForControl( pControl, pmxd->listLines );
     if( !pLine ) {
          return( FALSE );
     }

     if( pLine->Line.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS ) {
          return( TRUE );
     } else {
          return( FALSE );
     }

}

///////////////////////////////////////////////////////////////////////
//
// kmxlHandleGetUnsigned
//
//
// Handles getting an unsigned (32-bit) value for a control.  Note
// that signed 32-bit and boolean values are also retrieved via this
// handler.
//
//

NTSTATUS
kmxlHandleGetUnsigned(
    IN     LPDEVICEINFO                   DeviceInfo,
    IN     PMIXERDEVICE                   pmxd,
    IN     PMXLCONTROL                    pControl,
    IN     ULONG                          ulProperty,
    IN     LPMIXERCONTROLDETAILS          pmcd,
    IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
    IN     ULONG                          Flags
)
{
    NTSTATUS Status = STATUS_SUCCESS;
    LONG     Level;
    DWORD    dwLevel;
    ULONG    i;
    ULONG    Channel;
    MIXERMAPPING Mapping = MIXER_MAPPING_LOGRITHMIC;

    PAGED_CODE();

    DPFASSERT( IsValidMixerDevice(pmxd) );
    DPFASSERT( IsValidControl(pControl)  );

    if( paDetails == NULL ) {
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_SUCCESS );
    }

    //
    // Use a different mapping algorithm if this is a speaker
    // dest volume control.
    //

    if( kmxlIsSpeakerDestinationVolume( pmxd, pControl ) ) {
         Mapping = pmxd->Mapping;
    }

    //
    // Service the Mux
    //
    if ( pControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX) {

        Status = kmxlGetNodeProperty(
            pmxd->pfo,
            &KSPROPSETID_Audio,
            pControl->PropertyId,
            pControl->Id,
            0,
            NULL,
            &Level,
            sizeof( Level )
        );
        if( !NT_SUCCESS( Status ) ) {            
            DPF(DL_WARNING|FA_USER,( "kmxlHandleGetUnsigned( Ctrl=%d, Id=%d ) failed GET on MUX with %x",
                             pControl->Control.dwControlID,
                             pControl->Id,
                             Status ));
            DeviceInfo->mmr = MMSYSERR_ERROR;
            return( STATUS_SUCCESS );
        }

        DPF(DL_TRACE|FA_USER,( "kmxlHandleGetUnsigned( Ctrl=%d, Id=%d ) = %d [1]",
                   pControl->Control.dwControlID,
                   pControl->Id,
                   Level ));

        for( i = 0; i < pControl->Parameters.Count; i++ ) {
            if( (ULONG) Level == pControl->Parameters.pPins[ i ] ) {
//                APITRACE(( "1" ));
                paDetails[ i ].dwValue = 1;
            } else {
                paDetails[ i ].dwValue = 0;
//                APITRACE(( "1" ));
            }
        }

//        APITRACE(( "]\n" ));

    }
    else {

        paDetails->dwValue = 0; // initialize to zero for now so that the coalesced case works

        // Loop over the channels for now.  Fix this so that only one request is made.
        Channel = 0;
        do
        {
            Status = kmxlGetAudioNodeProperty(
                pmxd->pfo,
                ulProperty,
                pControl->Id,
                Channel,
                NULL,   0,                  // No extra input bytes
                &Level, sizeof( Level )
                );
            if ( !NT_SUCCESS( Status ) ) {                
                DPF(DL_TRACE|FA_USER,( "kmxlHandleGetUnsigned( Ctrl=%d [%s], Id=%d ) failed GET on MASTER channel with %x",
                           pControl->Control.dwControlID,
                           ControlTypeToString( pControl->Control.dwControlType ),
                           pControl->Id,
                           Status ));
                DPF(DL_WARNING|FA_PROPERTY, 
                    ( "GetAudioNodeProp failed on MASTER channel with %X for %s!",
                       Status,
                       ControlTypeToString( pControl->Control.dwControlType ) ) );
                DeviceInfo->mmr = MMSYSERR_ERROR;
                return( STATUS_SUCCESS );
            }

            if ( pControl->bScaled ) {
                dwLevel = kmxlVolLogToLinear( pControl, Level, Mapping, Channel );
            } else {
                dwLevel = (DWORD)Level;
            }

            if(  ( pmcd->cChannels == 1 ) &&
                !( pControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) ) {

                //
                // Coalesce values: If the user requests only 1 channel for a N channel
                // control, then return the greatest channel value.
                //
                if (dwLevel > paDetails->dwValue) {
                    paDetails->dwValue = dwLevel;
                }

            } else if (Channel < pmcd->cChannels) {

                paDetails[ Channel ].dwValue = dwLevel;
                DPF(DL_TRACE|FA_USER,( "kmxlHandleGetUnsigned( Ctrl=%d, Id=%d ) returning (Chan#%d) = (%x)",
                      pControl->Control.dwControlID,
                      pControl->Id,
                      Channel,
                      paDetails[ Channel ].dwValue
                      ));

            } else {
                // No need to keep trying
                break;
            }

            Channel++;

        } while ( Channel < pControl->NumChannels );
    }

    if( NT_SUCCESS( Status ) ) {
        DeviceInfo->mmr = MMSYSERR_NOERROR;
    } else {
        DeviceInfo->mmr = MMSYSERR_ERROR;
    }
    return( STATUS_SUCCESS );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlHandleGetMuteFromSuperMix
//
// Handles getting the mute state from a supermix node.
//

NTSTATUS
kmxlHandleGetMuteFromSuperMix(
    IN     LPDEVICEINFO                   DeviceInfo,
    IN     PMIXERDEVICE                   pmxd,
    IN     PMXLCONTROL                    pControl,
    IN     LPMIXERCONTROLDETAILS          pmcd,
    IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
    IN     ULONG                          Flags
)
{
    NTSTATUS Status;
    ULONG i;
    BOOL bMute = FALSE;

    PAGED_CODE();

    DPFASSERT( IsValidMixerDevice(pmxd) );
    ASSERT( pControl );

    ASSERT( pControl->Parameters.pMixCaps   );
    ASSERT( pControl->Parameters.pMixLevels );

    //
    // Read the current state of the supermix
    //

    Status = kmxlGetNodeProperty(
        pmxd->pfo,
        &KSPROPSETID_Audio,
        KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
        pControl->Id,
        0,
        NULL,
        pControl->Parameters.pMixLevels,
        pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
        );
    if( !NT_SUCCESS( Status ) ) {
        DPF(DL_WARNING|FA_USER,( "kmxlHandleGetMuteFromSupermix ( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
                   pControl->Control.dwControlID,
                   ControlTypeToString( pControl->Control.dwControlType ),
                   pControl->Id,
                   Status
                   ));
        DeviceInfo->mmr = MMSYSERR_ERROR;
        return( STATUS_SUCCESS );
    }

    for( i = 0; i < pControl->Parameters.Size; i++ ) {

        if( pControl->Parameters.pMixLevels[ i ].Mute )
        {
            bMute = TRUE;
            continue;
        }

        if( pControl->Parameters.pMixLevels[ i ].Level == LONG_MIN )
        {
            bMute = TRUE;
            continue;
        }

        bMute = FALSE;
        break;
    }

    paDetails->dwValue = (DWORD) bMute;
    DeviceInfo->mmr = MMSYSERR_NOERROR;
    return( STATUS_SUCCESS );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlHandleSetUnsigned
//
// Handles setting an unsigned (32-bit) value for a control.  Note
// that signed 32-bit and boolean values are also set via this
// handler.
//
//

NTSTATUS
kmxlHandleSetUnsigned(
    IN OUT LPDEVICEINFO                   DeviceInfo,
    IN     PMIXERDEVICE                   pmxd,
    IN     PMXLCONTROL                    pControl,
    IN     ULONG                          ulProperty,
    IN     LPMIXERCONTROLDETAILS          pmcd,
    IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
    IN     ULONG                          Flags
)
{
    NTSTATUS       Status = STATUS_SUCCESS;
    LONG           Level, Current;
    DWORD          dwValue;
    BOOL           bUniform, bEqual = TRUE;
    ULONG          i;
    ULONG          Channel;
    MIXERMAPPING   Mapping = MIXER_MAPPING_LOGRITHMIC;

    PAGED_CODE();

    DPFASSERT( IsValidMixerDevice(pmxd) );
    ASSERT( pControl  );

    if( paDetails == NULL ) {
        DPF(DL_WARNING|FA_USER,( "paDetails is NULL" ));
        DeviceInfo->mmr = MMSYSERR_INVALPARAM;
        return( STATUS_INVALID_PARAMETER );
    }

    bUniform = ( pControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) ||
               ( pmcd->cChannels == 1 );

    //
    // Use a different mapping if this control is a speaker destination
    // volume control.
    //

    if( kmxlIsSpeakerDestinationVolume( pmxd, pControl ) ) {
         Mapping = pmxd->Mapping;
    }

    //
    //  Service the mux
    //
    if ( pControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX) {

        // Proken APITRACE statement.
        //DPF(DL_TRACE|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%d, " ));


        // First validate the paDetails parameter and make sure it has the correct
        // format.  If not, then punt with an invalid parameter error.
                {
                LONG selectcount=0;

        for( i = 0; i < pmcd->cMultipleItems; i++ ) {
            if( paDetails[ i ].dwValue ) {
                selectcount++;
//                APITRACE(( "1" ));
            } else {
//                APITRACE(( "0" ));
            }

        }

        if (selectcount!=1) {
            DPF(DL_WARNING|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%d ) invalid paDetails parameter for SET on MUX",
                             pControl->Control.dwControlID,
                             ControlTypeToString( pControl->Control.dwControlType ),
                             pControl->Id));
            DeviceInfo->mmr = MMSYSERR_INVALPARAM;
            return( STATUS_SUCCESS );
                }

                }


        for( i = 0; i < pmcd->cMultipleItems; i++ ) {
            if( paDetails[ i ].dwValue ) {
//                APITRACE(( "1" ));
                Level = pControl->Parameters.pPins[ i ];
            } else {
//                APITRACE(( "0" ));
            }

        }

//        APITRACE(( " ). Setting pin %d on MUX.\n", Level ));

        Status = kmxlSetNodeProperty(
            pmxd->pfo,
            &KSPROPSETID_Audio,
            pControl->PropertyId,
            pControl->Id,
            0,
            NULL,
            &Level,
            sizeof( Level )
        );
        if( !NT_SUCCESS( Status ) ) {
            DPF(DL_WARNING|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%d ) failed SET on MUX with %x",
                             pControl->Control.dwControlID,
                             ControlTypeToString( pControl->Control.dwControlType ),
                             pControl->Id,
                             Status ));
            DeviceInfo->mmr = MMSYSERR_ERROR;
            return( STATUS_SUCCESS );
        }
        bEqual = FALSE;
    }
    else {
        // Loop over the channels for now.  Fix this so that only one request is made.
        Channel = 0;
        do
        {
            if( bUniform ) {
                //
                // Some controls are mono in the eyes of SNDVOL but are in
                // fact stereo.  This hack fixes this problem.
                //
                dwValue = paDetails[ 0 ].dwValue;
            } else if (Channel < pmcd->cChannels) {
                dwValue = paDetails[ Channel ].dwValue;
            } else {
                // No need to keep trying
                break;
            }

            if( pControl->bScaled ) {
                Level = kmxlVolLinearToLog( pControl, dwValue, Mapping, Channel );
            } else {
                Level = (LONG)dwValue;
            }

            Status = kmxlGetAudioNodeProperty(
                pmxd->pfo,
                ulProperty,
                pControl->Id,
                Channel,
                NULL,   0,                  // No extra input bytes
                &Current, sizeof( Current )
                );
            if( !NT_SUCCESS( Status ) ) {
                DPF(DL_WARNING|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%d ) failed GET on channel %d with %x",
                                 pControl->Control.dwControlID,
                                 ControlTypeToString( pControl->Control.dwControlType ),
                                 pControl->Id,
                                 Channel,
                                 Status ));
                DeviceInfo->mmr = MMSYSERR_ERROR;
                return( STATUS_SUCCESS );
            }

            if( Level != Current ) {

                bEqual = FALSE;

                Status = kmxlSetAudioNodeProperty(
                    pmxd->pfo,
                    ulProperty,
                    pControl->Id,
                    Channel,
                    NULL,   0,                  // No extra input bytes
                    &Level, sizeof( Level )
                    );
                if( !NT_SUCCESS( Status ) ) {
                    DPF(DL_WARNING|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%x ) failed SET on channel %d with %x",
                                     pControl->Control.dwControlID,
                                     ControlTypeToString( pControl->Control.dwControlType ),
                                     pControl->Id,
                                     Channel,
                                     Status ));
                    DeviceInfo->mmr = MMSYSERR_ERROR;
                    return( STATUS_SUCCESS );
                }

                DPF(DL_TRACE|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d, Id=%d ) using (%x) on Chan#%d",
                          pControl->Control.dwControlID,
                          pControl->Id,
                          paDetails[ Channel ].dwValue,
                          Channel
                        ));
            }

            Channel++;

        } while ( Channel < pControl->NumChannels );
    }

    if( NT_SUCCESS( Status ) ) {

        DeviceInfo->mmr = MMSYSERR_NOERROR;

        if( Flags & MIXER_FLAG_PERSIST ) {

            kmxlPersistControl(
                pmxd->pfo,
                pmxd,
                pControl,
                paDetails
                );
        }

        if( !bEqual && !( Flags & MIXER_FLAG_NOCALLBACK ) ) {
            kmxlNotifyControlChange( DeviceInfo, pmxd, pControl );
        }

    } else {
        DeviceInfo->mmr = MMSYSERR_ERROR;
    }

    return( STATUS_SUCCESS );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlHandleSetMuteFromSuperMix
//
//  Handles setting the mute state using a supermixer.
//
//

NTSTATUS
kmxlHandleSetMuteFromSuperMix(
    IN OUT LPDEVICEINFO                   DeviceInfo,
    IN     PMIXERDEVICE                   pmxd,
    IN     PMXLCONTROL                    pControl,
    IN     LPMIXERCONTROLDETAILS          pmcd,
    IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
    IN     ULONG                          Flags
)
{
    NTSTATUS Status;
    ULONG i;

    PAGED_CODE();

    DPFASSERT( IsValidMixerDevice(pmxd) );
    ASSERT( pControl );

    ASSERT( pControl->Parameters.pMixCaps   );
    ASSERT( pControl->Parameters.pMixLevels );

    if( paDetails->dwValue ) {

        //
        // Query the current values from the supermix and save those away.
        // These values will be used to restore the supermix to the state
        // we found it prior to muting.
        //

        Status = kmxlGetNodeProperty(
            pmxd->pfo,
            &KSPROPSETID_Audio,
            KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
            pControl->Id,
            0,
            NULL,
            pControl->Parameters.pMixLevels,
            pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
            );
        if( !NT_SUCCESS( Status ) ) {
            DPF(DL_WARNING|FA_USER,( "kmxlHandleSetMuteFromSuperMix( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
                             pControl->Control.dwControlID,
                             ControlTypeToString( pControl->Control.dwControlType ),
                             pControl->Id,
                             Status ));
            DeviceInfo->mmr = MMSYSERR_ERROR;
            return( STATUS_SUCCESS );
        }

        //
        // For any entry in the table that supports muting, mute it.
        //

        for( i = 0; i < pControl->Parameters.Size; i++ ) {

            if( pControl->Parameters.pMixCaps->Capabilities[ i ].Mute ) {
                pControl->Parameters.pMixLevels[ i ].Mute = TRUE;
            }
        }

        //
        // Set this new supermixer state.
        //

        Status = kmxlSetNodeProperty(
            pmxd->pfo,
            &KSPROPSETID_Audio,
            KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
            pControl->Id,
            0,
            NULL,
            pControl->Parameters.pMixLevels,
            pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
            );
        if( !NT_SUCCESS( Status ) ) {
            DPF(DL_WARNING|FA_USER,( "kmxlHandleSetMuteFromSuperMix( Ctrl=%d [%s], Id=%d ) failed SET on MIX_LEVEL_TABLE with %x",
                             pControl->Control.dwControlID,
                             ControlTypeToString( pControl->Control.dwControlType ),
                             pControl->Id,
                             Status ));
            DeviceInfo->mmr = MMSYSERR_ERROR;
            return( STATUS_SUCCESS );
        }

    } else {

        Status = kmxlGetNodeProperty(
            pmxd->pfo,
            &KSPROPSETID_Audio,
            KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
            pControl->Id,
            0,
            NULL,
            pControl->Parameters.pMixLevels,
            pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
            );
        if( !NT_SUCCESS( Status ) ) {
            DPF(DL_WARNING|FA_USER,( "kmxlHandleSetMuteFromSuperMix( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
                             pControl->Control.dwControlID,
                             ControlTypeToString( pControl->Control.dwControlType ),
                             pControl->Id,
                             Status ));
            DeviceInfo->mmr = MMSYSERR_ERROR;
            return( STATUS_SUCCESS );
        }

        //
        // For any entry in the table that supports muting, mute it.
        //

        for( i = 0; i < pControl->Parameters.Size; i++ ) {

            if( pControl->Parameters.pMixCaps->Capabilities[ i ].Mute ) {
                pControl->Parameters.pMixLevels[ i ].Mute = FALSE;
            }
        }

        //
        // Set this new supermixer state.
        //

        Status = kmxlSetNodeProperty(
            pmxd->pfo,
            &KSPROPSETID_Audio,
            KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
            pControl->Id,
            0,
            NULL,
            pControl->Parameters.pMixLevels,
            pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
            );
        if( !NT_SUCCESS( Status ) ) {
            DPF(DL_WARNING|FA_USER,( "kmxlHandleSetMuteFromSuperMix( Ctrl=%d [%s], Id=%d ) failed SET on MIX_LEVEL_TABLE with %x",
                             pControl->Control.dwControlID,
                             ControlTypeToString( pControl->Control.dwControlType ),
                             pControl->Id,
                             Status ));
            DeviceInfo->mmr = MMSYSERR_ERROR;
            return( STATUS_SUCCESS );
        }

    }

    if( NT_SUCCESS( Status ) ) {
        if( Flags & MIXER_FLAG_PERSIST ) {

            kmxlPersistControl(
                pmxd->pfo,
                pmxd,
                pControl,
                paDetails
                );

        }

        kmxlNotifyControlChange( DeviceInfo, pmxd, pControl );
        DeviceInfo->mmr = MMSYSERR_NOERROR;
    } else {
        DeviceInfo->mmr = MMSYSERR_ERROR;
    }

    return( STATUS_SUCCESS );
}

#ifdef SUPERMIX_AS_VOL
///////////////////////////////////////////////////////////////////////
//
// kmxlHandleGetVolumeFromSuperMix
//
//

NTSTATUS
kmxlHandleGetVolumeFromSuperMix(
    IN     LPDEVICEINFO                   DeviceInfo,
    IN     PMIXERDEVICE                   pmxd,
    IN     PMXLCONTROL                    pControl,
    IN     LPMIXERCONTROLDETAILS          pmcd,
    IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
    IN     ULONG                          Flags
)
{
    NTSTATUS Status;
    ULONG i, Channels, Index, MaxChannel = 0;
    LONG  Max = LONG_MIN; // -Inf dB

    PAGED_CODE();

    DPFASSERT( IsValidMixerDevice(pmxd) );
    ASSERT( pControl  );
    ASSERT( pmcd      );
    ASSERT( paDetails );

    Status = kmxlGetNodeProperty(
        pmxd->pfo,
        &KSPROPSETID_Audio,
        KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
        pControl->Id,
        0,
        NULL,
        pControl->Parameters.pMixLevels,
        pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
        );
    if( !NT_SUCCESS( Status ) ) {
        DPF(DL_WARNING|FA_USER,( "kmxlHandleGetVolumeFromSuperMix( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
                         pControl->Control.dwControlID,
                         ControlTypeToString( pControl->Control.dwControlType ),
                         pControl->Id,
                         Status ));
        DeviceInfo->mmr = MMSYSERR_ERROR;
        return( STATUS_SUCCESS );
    }

    //
    // Count the number of channels
    //

    for( i = 0, Channels = 0;
         i < pControl->Parameters.Size;
         i += pControl->Parameters.pMixCaps->OutputChannels + 1,
         Channels++ )
    {
        if( pControl->Parameters.pMixLevels[ i ].Level > Max ) {
            Max = pControl->Parameters.pMixLevels[ i ].Level;
            MaxChannel = Channels;
        }
    }

    //
    // Return the translated volume levels
    //

    if( ( pmcd->cChannels == 1 ) && ( Channels > 1 ) ) {

        //
        // As per SB16 sample, if the caller wants only 1 channel but
        // the control is multichannel, return the maximum of all the
        // channels.
        //

        paDetails->dwValue = kmxlVolLogToLinear(
            pControl,
            Max,
            MIXER_MAPPING_LOGRITHMIC,
            MaxChannel
            );
    } else {

        //
        // Translate each of the channel value into linear and
        // store them away.
        //

        for( i = 0; i < pmcd->cChannels; i++ ) {

            Index = i * ( pControl->Parameters.pMixCaps->OutputChannels + 1 );
            paDetails[ i ].dwValue = kmxlVolLogToLinear(
                pControl,
                pControl->Parameters.pMixLevels[ Index ].Level,
                MIXER_MAPPING_LOGRITHMIC,
                i
                );
        }

    }

    DeviceInfo->mmr = MMSYSERR_NOERROR;
    return( STATUS_SUCCESS );
}

///////////////////////////////////////////////////////////////////////
//
// kmxlHandleSetVolumeFromSuperMix
//
//

NTSTATUS
kmxlHandleSetVolumeFromSuperMix(
    IN     LPDEVICEINFO                   DeviceInfo,
    IN     PMIXERDEVICE                   pmxd,
    IN     PMXLCONTROL                    pControl,
    IN     LPMIXERCONTROLDETAILS          pmcd,
    IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
    IN     ULONG                          Flags
)
{
    NTSTATUS Status;
    ULONG i, Index;

    PAGED_CODE();

    DPFASSERT( IsValidMixerDevice(pmxd) );
    ASSERT( pControl  );
    ASSERT( pmcd      );
    ASSERT( paDetails );

    //
    // Query the current values for the mix levels.
    //

    Status = kmxlGetNodeProperty(
        pmxd->pfo,
        &KSPROPSETID_Audio,
        KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
        pControl->Id,
        0,
        NULL,
        pControl->Parameters.pMixLevels,
        pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
        );
    if( !NT_SUCCESS( Status ) ) {
        DPF(DL_WARNING|FA_USER,( "kmxlHandleSetVolumeFromSuperMix( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
                         pControl->Control.dwControlID,
                         ControlTypeToString( pControl->Control.dwControlType ),
                         pControl->Id,
                         Status ));
        DeviceInfo->mmr = MMSYSERR_ERROR;
        return( STATUS_SUCCESS );
    }

    //
    // Adjust the values on the diagonal to those the user specified.
    //

    for( i = 0; i < pmcd->cChannels; i++ ) {

        Index = i * ( pControl->Parameters.pMixCaps->OutputChannels + 1 );
        pControl->Parameters.pMixLevels[ Index ].Level = kmxlVolLinearToLog(
            pControl,
            paDetails[ i ].dwValue,
            MIXER_MAPPING_LOGRITHMIC,
            i
            );
    }

    //
    // Set these new values.
    //

    Status = kmxlSetNodeProperty(
        pmxd->pfo,
        &KSPROPSETID_Audio,
        KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
        pControl->Id,
        0,
        NULL,
        pControl->Parameters.pMixLevels,
        pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL ),
        );

    if( NT_SUCCESS( Status ) ) {
        DeviceInfo->mmr = MMSYSERR_NOERROR;
    } else {
        DPF(DL_WARNING|FA_USER,( "kmxlHandleSetVolumeFromSuperMix( Ctrl=%d [%s], Id=%d ) failed SET on MIX_LEVEL_TABLE with %x",
                         pControl->Control.dwControlID,
                         ControlTypeToString( pControl->Control.dwControlType ),
                         pControl->Id,
                         Status ));
        DeviceInfo->mmr = MMSYSERR_ERROR;
    }
    return( STATUS_SUCCESS );
}
#endif // SUPERMIX_AS_VOL

///////////////////////////////////////////////////////////////////////
//
// kmxlNotifyLineChange
//
//

VOID
kmxlNotifyLineChange(
    OUT LPDEVICEINFO                  DeviceInfo,
    IN PMIXERDEVICE                   pmxd,
    IN PMXLLINE                       pLine,
    IN LPMIXERCONTROLDETAILS_UNSIGNED paDetails
)
{
    PAGED_CODE();

    ASSERT( (DeviceInfo->dwCallbackType&MIXER_LINE_CALLBACK) == 0 );

    DeviceInfo->dwLineID=pLine->Line.dwLineID;
    DeviceInfo->dwCallbackType|=MIXER_LINE_CALLBACK;
}


///////////////////////////////////////////////////////////////////////
//
// kmxlNotifyControlChange
//
//

VOID
kmxlNotifyControlChange(
    OUT LPDEVICEINFO  DeviceInfo,
    IN PMIXERDEVICE   pmxd,
    IN PMXLCONTROL    pControl
)
{
    WRITE_CONTEXT* pwc;

    PAGED_CODE();

    //
    // If there are no open instances, there is no reason to even attempt
    // a callback... no one is listening.
    //

    ExAcquireFastMutex( &ReferenceCountMutex );

    if( ReferenceCount == 0 ) {
        ExReleaseFastMutex( &ReferenceCountMutex );
        return;
    }

    ExReleaseFastMutex( &ReferenceCountMutex );


    {
        PMXLLINE    pLine;
        PMXLCONTROL pCtrl;

        LONG callbackcount;

        callbackcount=0;

        pLine = kmxlFirstInList( pmxd->listLines );
        while( pLine ) {

            pCtrl = kmxlFirstInList( pLine->Controls );
            while( pCtrl ) {

                if ( pCtrl->Id == pControl->Id ) {

                    //ASSERT( (DeviceInfo->dwCallbackType&MIXER_CONTROL_CALLBACK) == 0 );
                    ASSERT( callbackcount < MAXCALLBACKS );

                    if ( callbackcount < MAXCALLBACKS ) {
                        (DeviceInfo->dwID)[callbackcount++]=pCtrl->Control.dwControlID;
                        }

                    DeviceInfo->dwCallbackType|=MIXER_CONTROL_CALLBACK;

                    }
                pCtrl = kmxlNextControl( pCtrl );
            }
            pLine = kmxlNextLine( pLine );
        }

    DeviceInfo->ControlCallbackCount=callbackcount;

    }
}