File:  [WindowsNT SDKs] / ntddk / src / mmedia / sndblst / driver / config.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

/*++

Copyright (c) 1991  Microsoft Corporation

Module Name:

    config.c

Abstract:

    This module contains code configuration code for the initialization phase
    of the Microsoft Sound System device driver.

Author:

    Robin Speed (RobinSp) 17-Oct-1992

Environment:

    Kernel mode

Revision History:

--*/


#include "sound.h"

//
// Internal routines
//
NTSTATUS
SoundInitIoPort(
    IN OUT PGLOBAL_DEVICE_INFO pGDI,
    IN OUT PSB_CONFIG_DATA ConfigData
);
NTSTATUS
SoundPortValid(
    IN OUT PGLOBAL_DEVICE_INFO pGDI,
    IN OUT PULONG Port
);
NTSTATUS
SoundInitDmaChannel(
    IN OUT PGLOBAL_DEVICE_INFO pGDI,
    IN OUT PULONG DmaChannel,
    IN     ULONG DmaBufferSize
);
NTSTATUS
SoundDmaChannelValid(
    IN OUT PGLOBAL_DEVICE_INFO pGDI,
    IN OUT PULONG DmaChannel
);
NTSTATUS
SoundInitInterrupt(
    IN OUT PGLOBAL_DEVICE_INFO pGDI,
    IN OUT PULONG Interrupt
);
NTSTATUS
SoundInterruptValid(
    IN OUT PGLOBAL_DEVICE_INFO pGDI,
    IN OUT PULONG Interrupt
);
VOID
SoundSetVersion(
    IN PGLOBAL_DEVICE_INFO pGlobalInfo,
    IN ULONG DSPVersion
);

#ifdef ALLOC_PRAGMA
#pragma alloc_text(init,SoundSetVersion)
#pragma alloc_text(init,SoundInitHardwareConfig)
#pragma alloc_text(init,SoundInitIoPort)
#pragma alloc_text(init,SoundInitDmaChannel)
#pragma alloc_text(init,SoundInitInterrupt)
#pragma alloc_text(init,SoundSaveConfig)
#pragma alloc_text(init,SoundReadConfiguration)
#endif


VOID
SoundSetVersion(
    IN PGLOBAL_DEVICE_INFO pGlobalInfo,
    IN ULONG DSPVersion
)
/*++

Routine Description :

    Sets a version DWORD into the registry as a pseudo return code
    to sndblst.drv

    As a side effect the key to the registry entry is closed.

Arguments :

    pGlobalInfo - Our driver global info

    DSPVersion - the version number we want to set

Return Value :

    None

--*/
{
    UNICODE_STRING VersionString;

    RtlInitUnicodeString(&VersionString, L"DSP Version");
    if (pGlobalInfo->RegistryPathName) {
        NTSTATUS SetStatus;

        SetStatus =

        SoundWriteRegistryDWORD(pGlobalInfo->RegistryPathName,
                                L"DSP Version",
                                DSPVersion);

        if (!NT_SUCCESS(SetStatus)) {
            dprintf1(("Failed to write version - status %x", SetStatus));
        }
    }
}


NTSTATUS
SoundInitHardwareConfig(
    IN OUT PGLOBAL_DEVICE_INFO pGDI,
    IN     PSB_CONFIG_DATA ConfigData
)
{

    NTSTATUS Status;

    //
    // Check the input source
    //

    if (ConfigData->InputSource > INPUT_OUTPUT) {
        return STATUS_DEVICE_CONFIGURATION_ERROR;
    }

    pGDI->Hw.InputSource = ConfigData->InputSource;

    //
    // Find port
    //

    Status = SoundInitIoPort(pGDI, ConfigData);

    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    //
    // Find interrupt
    //

    Status = SoundInitInterrupt(pGDI, &ConfigData->InterruptNumber);

    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    //
    // Find DMA channel
    //

    Status = SoundInitDmaChannel(pGDI, &ConfigData->DmaChannel,
                                 ConfigData->DmaBufferSize);

    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    //
    // Report the sound-blaster version number (and a flag
    // to say if it's a Thunderboard.
    // We do this via an entry in our registry node - under
    // our device-specific section.  If this fails then configuration
    // won't work so well but the driver will work fine.
    //
    // We use the registry handle generated by SoundReadConfiguration

    {
        ULONG DSPVersion;

        DSPVersion = pGDI->Hw.DSPVersion;

        //
        // If it's a pro audio spectrum set a bit to say it is
        //

        if (pGDI->ProAudioSpectrum) {
            DSPVersion |= 0x800;
        } else {
            //
            // If it's a Thunderboard following comparison will fail.
            // There's not much point having a constant for a flag
            // because there's no logical way to share info between
            // sndblst.sys and sndblst.drv
            //

            if (pGDI->Hw.ThunderBoard) {
                DSPVersion |= 0x8000;

                //
                // Note - it MAY be a pro spectrum !
                //
            }
        }

        //
        // Put the version number in the registry (if we can)
        //

        SoundSetVersion(pGDI, DSPVersion);
    }


    //
    // turn on the speaker
    //

    dspSpeakerOn(&pGDI->Hw);

    return STATUS_SUCCESS;

}




NTSTATUS
SoundInitIoPort(
    IN OUT PGLOBAL_DEVICE_INFO pGDI,
    IN OUT PSB_CONFIG_DATA ConfigData
)
{
    NTSTATUS Status;

    //
    // Find where our device is mapped
    //

    pGDI->Hw.PortBase = SoundMapPortAddress(
                               pGDI->BusType,
                               pGDI->BusNumber,
                               ConfigData->Port,
                               NUMBER_OF_SOUND_PORTS,
                               &pGDI->MemType);

    //
    // Check and see if the hardware is happy
    //

    //
    // Check the SoundBlaster is where we think it is and get
    // the dsp version code.
    //

    if (!dspReset(&pGDI->Hw)) {
        NTSTATUS PasStatus = STATUS_DEVICE_CONFIGURATION_ERROR;

#ifdef PAS16 // There's a proper driver now

        //
        // Try to wake up any lurking Pro audio spectrums
        // that are asleep
        //

        PasStatus = FindPasHardware(pGDI, ConfigData);

#endif // PAS16

        if (!NT_SUCCESS(PasStatus) || !dspReset(&pGDI->Hw)) {
            pGDI->Hw.DSPVersion = 0;
            SoundSetVersion(pGDI, 0x4000); // Means port was wrong
            return STATUS_DEVICE_CONFIGURATION_ERROR;
        }

        pGDI->ProAudioSpectrum = TRUE;
    }

    pGDI->Hw.DSPVersion = dspGetVersion(&pGDI->Hw);

    //
    // Check for Thunderboards and Pro Spectrums
    //

    if (dspGetVersion(&pGDI->Hw) != pGDI->Hw.DSPVersion) {
        pGDI->Hw.ThunderBoard = TRUE;

#ifdef PAS16 // We now have a proper driver for this
        //
        // See if this guy is a Pro audio spectrum.  By this
        // stage it will be woken up but we still need to tell if
        // it is one and set its features and mixer.
        //

        if (pGDI->ProAudioSpectrum ||
            NT_SUCCESS(FindPasHardware(pGDI, ConfigData))) {

            pGDI->ProAudioSpectrum = TRUE;
            InitPasAndMixer(&pGDI->PASInfo, ConfigData);
        }
#endif // PAS16
    }


    //
    // Set up version - dependent stuff
    //
    if (pGDI->Hw.DSPVersion >= MIN_DSP_VERSION) {

        pGDI->MinHz = 4000;

        if (SB1(&pGDI->Hw)) {
            pGDI->MaxInHz = 12000;
            pGDI->MaxOutHz = 23000;
        } else {
            if (!SBPRO(&pGDI->Hw)) {
                pGDI->MaxInHz = 13000;
                pGDI->MaxOutHz = 23000;
            } else {
                pGDI->MaxInHz = 23000;
                pGDI->MaxOutHz = 23000;
            }
        }
        return STATUS_SUCCESS;
    } else {
        return STATUS_DEVICE_CONFIGURATION_ERROR;
    }
}



NTSTATUS
SoundInitDmaChannel(
    IN OUT PGLOBAL_DEVICE_INFO pGDI,
    IN OUT PULONG DmaChannel,
    IN     ULONG DmaBufferSize
)
{
    NTSTATUS Status;

    DEVICE_DESCRIPTION DeviceDescription;      // DMA adapter object

    //
    // See if we can get this channel
    //

    //
    // Zero the device description structure.
    //

    RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));

    //
    // Get the adapter object for this card.
    //

    DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
    DeviceDescription.AutoInitialize = !SB1(&pGDI->Hw);
    DeviceDescription.ScatterGather = FALSE;
    DeviceDescription.DmaChannel = *DmaChannel;
    DeviceDescription.InterfaceType = Isa;    // Must use Isa DMA
    DeviceDescription.DmaWidth = Width8Bits;
    DeviceDescription.DmaSpeed = Compatible;
    DeviceDescription.MaximumLength = DmaBufferSize;
    DeviceDescription.BusNumber = pGDI->BusNumber;

    return SoundGetCommonBuffer(&DeviceDescription, &pGDI->WaveInfo.DMABuf);
}



NTSTATUS
SoundInitInterrupt(
    IN OUT PGLOBAL_DEVICE_INFO pGDI,
    IN OUT PULONG Interrupt
)
{
    NTSTATUS Status;

    //
    // See if we can get this interrupt
    //


    Status = SoundConnectInterrupt(
               *Interrupt,
               pGDI->BusType,
               pGDI->BusNumber,
               SoundISR,
               (PVOID)pGDI,
               INTERRUPT_MODE,
               IRQ_SHARABLE,
               &pGDI->WaveInfo.Interrupt);

    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    //
    // Check if our interrupts are working.
    // To do this we write a special code to make the card generate
    // an interrupt.  We wait a reasonable amount of time for
    // this to happen.  This is tried 10 times.
    //
    {
        int i;
        int j;
        ULONG CurrentCount;
        CurrentCount = pGDI->InterruptsReceived + 1;

        for (i = 0; i < 10; i++, CurrentCount++) {

            // Tell the card to generate an interrupt

            dspWrite(&pGDI->Hw, DSP_GENERATE_INT);

            //
            // The interrupt routine will increment the InterruptsReceived
            // field if we get an interrupt.
            //

            for (j = 0; j < 1000; j++) {
                if (CurrentCount == pGDI->InterruptsReceived) {
                    break;
                }
                KeStallExecutionProcessor(10);
            }

            //
            // This test catches both too many and too few interrupts
            //

            if (CurrentCount != pGDI->InterruptsReceived) {

                dprintf1(("Sound blaster configured at wrong interrupt"));

                SoundSetVersion(pGDI, 0x2000); // Means wrong interrupt
                return STATUS_DEVICE_CONFIGURATION_ERROR;
            }
        }
    }

    return STATUS_SUCCESS;
}



NTSTATUS
SoundSaveConfig(
    IN  PWSTR DeviceKey,
    IN  ULONG Port,
    IN  ULONG DmaChannel,
    IN  ULONG Interrupt,
    IN  ULONG InputSource
)
{
    NTSTATUS Status;

    Status = SoundWriteRegistryDWORD(DeviceKey, SOUND_REG_PORT, Port);

    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    Status = SoundWriteRegistryDWORD(DeviceKey, SOUND_REG_DMACHANNEL, DmaChannel);

    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    Status = SoundWriteRegistryDWORD(DeviceKey, SOUND_REG_INTERRUPT, Interrupt);

    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    Status = SoundWriteRegistryDWORD(DeviceKey, SOUND_REG_INPUTSOURCE, InputSource);

    if (!NT_SUCCESS(Status)) {
        return Status;
    }

    //
    // Make sure the config routine sees the data
    //
}


VOID
SoundSaveVolume(
    PGLOBAL_DEVICE_INFO pGDI
)
{
    NTSTATUS Status;

    //
    // Write out left and right volume settings for each device
    //

    int i;
    for (i = 0; i < NumberOfDevices; i++) {
        PLOCAL_DEVICE_INFO pLDI;

        if (pGDI->DeviceObject[i]){
            pLDI = (PLOCAL_DEVICE_INFO)pGDI->DeviceObject[i]->DeviceExtension;
            SoundSaveDeviceVolume(pLDI, pGDI->RegistryPathName);
        }

    }

    //
    // Make sure the volume settings make it do disk
    //

    SoundFlushRegistryKey(pGDI->RegistryPathName);
}



NTSTATUS
SoundReadConfiguration(
    IN  PWSTR ValueName,
    IN  ULONG ValueType,
    IN  PVOID ValueData,
    IN  ULONG ValueLength,
    IN  PVOID Context,
    IN  PVOID EntryContext
)
/*++

Routine Description :

    Return configuration information for our device

Arguments :

    ConfigData - where to store the result

Return Value :

    NT status code - STATUS_SUCCESS if no problems

--*/
{
    PSB_CONFIG_DATA ConfigData;

    ConfigData = Context;

    if (ValueType == REG_DWORD) {

        if (wcsicmp(ValueName, SOUND_REG_PORT)  == 0) {
            ConfigData->Port = *(PULONG)ValueData;
            dprintf3(("Read Port Base : %x", ConfigData->Port));
        }

        else if (wcsicmp(ValueName, SOUND_REG_INTERRUPT)  == 0) {
            ConfigData->InterruptNumber = *(PULONG)ValueData;
            dprintf3(("Read Interrupt : %x", ConfigData->InterruptNumber));
        }

        else if (wcsicmp(ValueName, SOUND_REG_DMACHANNEL)  == 0) {
            ConfigData->DmaChannel = *(PULONG)ValueData;
            dprintf3(("Read DMA Channel : %x", ConfigData->DmaChannel));
        }

        else if (wcsicmp(ValueName, SOUND_REG_DMABUFFERSIZE)  == 0) {
            ConfigData->DmaBufferSize = *(PULONG)ValueData;
            dprintf3(("Read DMA Channel : %x", ConfigData->DmaBufferSize));
        }

        else if (wcsicmp(ValueName, SOUND_REG_INPUTSOURCE)  == 0) {
            ConfigData->InputSource = *(PULONG)ValueData;
            dprintf3(("Read Input Source : %s",
                     ConfigData->InputSource == INPUT_LINEIN ? "Line in" :
                     ConfigData->InputSource == INPUT_AUX ? "Aux" :
                     ConfigData->InputSource == INPUT_MIC ? "Microphone" :
                     ConfigData->InputSource == INPUT_OUTPUT ? "Output" :
                     "Invalid input source"
                     ));
        }

        else {
            int i;
            for (i = 0; i < NumberOfDevices; i++) {
                if (DeviceInit[i].LeftVolumeName != NULL &&
                    wcsicmp(ValueName, DeviceInit[i].LeftVolumeName) == 0) {
                    ConfigData->Volume[i].Left = *(PULONG)ValueData;

                    dprintf3(("%ls = %8X", DeviceInit[i].LeftVolumeName,
                              ConfigData->Volume[i].Left));
                    break;
                }
                if (DeviceInit[i].RightVolumeName != NULL &&
                    wcsicmp(ValueName, DeviceInit[i].RightVolumeName) == 0) {
                    ConfigData->Volume[i].Right = *(PULONG)ValueData;

                    dprintf3(("%ls = %8X", DeviceInit[i].RightVolumeName,
                              ConfigData->Volume[i].Right));
                    break;
                }
            }
        }

    }

    return STATUS_SUCCESS;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.