|
|
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;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.