Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1180 lines
30 KiB

/*****************************************************************************
Copyright (c) 1992-1994 Microsoft Corporation
Module Name:
init.c
Abstract:
This module contains code for the initialization phase of the
Sound blaster device driver.
Environment:
Kernel mode
Revision History:
****************************************************************************/
#include "sound.h"
NTSTATUS
SoundInitDmaChannel(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PSB_CONFIG_DATA ConfigData
);
NTSTATUS
SoundInitInterrupt(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PSB_CONFIG_DATA ConfigData
);
NTSTATUS
SoundInitIoPort(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PSB_CONFIG_DATA ConfigData
);
NTSTATUS
SoundInitMPU401(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PSB_CONFIG_DATA ConfigData
);
BOOLEAN
SoundSetMPU401UARTMode(
IN PSOUND_HARDWARE pHw
);
#ifdef SB_CD
BOOLEAN
SoundCheckForSBCD(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN ULONG Port
);
#endif // SB_CD
BOOLEAN
SoundMPU401Valid(PSOUND_HARDWARE pHw);
//
// Remove initialization stuff from resident memory
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,SoundInitHardwareConfig)
#pragma alloc_text(INIT,SoundInitIoPort)
#pragma alloc_text(INIT,SoundInitDmaChannel)
#pragma alloc_text(INIT,SoundInitInterrupt)
#pragma alloc_text(INIT,SoundInitMPU401)
#pragma alloc_text(INIT,SoundMPU401Valid)
#pragma alloc_text(INIT,SoundSetMPU401UARTMode)
#pragma alloc_text(INIT,SoundSaveConfig)
#pragma alloc_text(INIT,SoundReadConfiguration)
#endif
NTSTATUS
SoundInitHardwareConfig(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN PSB_CONFIG_DATA ConfigData
)
/*++
Routine Description :
Initialize the sound blaster driver hardware configuration
Arguments :
pGDI - Our device instance data
ConfigData - Configuration data read from the registry (or
defaults)
Return Value :
NTSTATUS value
--*/
{
NTSTATUS Status;
//
// Find port
//
Status = SoundInitIoPort(pGDI, ConfigData);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// Don't load if we're being asked to configure
//
if (ConfigData->LoadType == SOUND_LOADTYPE_CONFIG) {
pGDI->LoadStatus = SOUND_CONFIG_OK;
//
// If it's an SB16 update the current interrupt and
// DMA channel(s)
//
{
if (SB16(&pGDI->Hw)) {
UCHAR PortVal;
OUTPORT(&pGDI->Hw, MIX_ADDR_PORT, MIX_INTERRUPT_SELECT_REG);
PortVal = INPORT(&pGDI->Hw, MIX_DATA_PORT);
switch (PortVal & 0x0F) {
case 0x01:
ConfigData->InterruptNumber = 9;
break;
case 0x02:
ConfigData->InterruptNumber = 5;
break;
case 0x04:
ConfigData->InterruptNumber = 7;
break;
case 0x08:
ConfigData->InterruptNumber =10;
break;
}
SoundWriteRegistryDWORD(pGDI->RegistryPathName,
SOUND_REG_INTERRUPT,
ConfigData->InterruptNumber);
OUTPORT(&pGDI->Hw, MIX_ADDR_PORT, MIX_DMA_SELECT_REG);
PortVal = INPORT(&pGDI->Hw, MIX_DATA_PORT);
switch (PortVal & 0x0B) {
case 0x01:
ConfigData->DmaChannel = 0;
break;
case 0x02:
ConfigData->DmaChannel = 1;
break;
case 0x08:
ConfigData->DmaChannel = 3;
break;
}
SoundWriteRegistryDWORD(pGDI->RegistryPathName,
SOUND_REG_DMACHANNEL,
ConfigData->DmaChannel);
switch (PortVal & 0xE0) {
case 0x20:
ConfigData->DmaChannel16 = 5;
break;
case 0x40:
ConfigData->DmaChannel16 = 6;
break;
case 0x80:
ConfigData->DmaChannel16 = 7;
break;
}
SoundWriteRegistryDWORD(pGDI->RegistryPathName,
SOUND_REG_DMACHANNEL16,
ConfigData->DmaChannel16);
}
}
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
//
// Check MPU401 if SB16 - do this BEFORE we enable interrupts
//
if (SB16(&pGDI->Hw)) {
Status = SoundInitMPU401(pGDI, ConfigData);
if (!NT_SUCCESS(Status)) {
return Status;
}
}
//
// Find interrupt
//
Status = SoundInitInterrupt(pGDI, ConfigData);
if (!NT_SUCCESS(Status)) {
return Status;
}
if (MPU401(&pGDI->Hw)) {
//
// Now we can see if the MPU401 UART Mode is working.
//
if (!SoundSetMPU401UARTMode(&pGDI->Hw)) {
pGDI->LoadStatus = SOUND_CONFIG_BAD_MPU401_PORT;
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
}
//
// Find DMA channel (s)
//
Status = SoundInitDmaChannel(pGDI, ConfigData);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// turn on the speaker
//
dspSpeakerOn(&pGDI->Hw);
return STATUS_SUCCESS;
}
NTSTATUS
SoundInitMPU401(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PSB_CONFIG_DATA ConfigData
)
{
NTSTATUS Status;
pGDI->LoadStatus = SOUND_CONFIG_BAD_MPU401_PORT;
if (ConfigData->MPU401Port == (ULONG)-1) {
return STATUS_SUCCESS;
}
if (ConfigData->MPU401Port != 0x300 &&
ConfigData->MPU401Port != 0x330) {
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
//
// Check we're going to be allowed to use this port or whether
// some other device thinks it owns this hardware
//
Status = SoundReportResourceUsage(
pGDI->DeviceObject[WaveInDevice], // As good as any device to own
// it
pGDI->BusType,
pGDI->BusNumber,
NULL,
0,
FALSE,
NULL,
&ConfigData->MPU401Port,
NUMBER_OF_MPU401_PORTS);
if (!NT_SUCCESS(Status)) {
pGDI->LoadStatus = SOUND_CONFIG_MPU401_PORT_INUSE;
return Status;
}
//
// Find where our device is mapped
//
pGDI->Hw.MPU401.PortBase = SoundMapPortAddress(
pGDI->BusType,
pGDI->BusNumber,
ConfigData->MPU401Port,
NUMBER_OF_MPU401_PORTS,
&pGDI->MemType);
//
// Check no other SB card has this IO port. NOTE that unfortunately
// IoReportResourceUsage won't give us a conflict here for some
// reason
//
{
PGLOBAL_DEVICE_INFO pGDISearch;
for (pGDISearch = pGDI->Next; pGDISearch != pGDI;
pGDISearch = pGDISearch->Next) {
if (pGDISearch->Hw.MPU401.PortBase == pGDI->Hw.MPU401.PortBase) {
pGDI->LoadStatus = SOUND_CONFIG_MPU401_PORT_INUSE;
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
}
}
//
// Check and see if the hardware is happy
//
if (!SoundMPU401Valid(&pGDI->Hw)) {
if (pGDI->MemType == 0) {
MmUnmapIoSpace(pGDI->Hw.MPU401.PortBase, NUMBER_OF_MPU401_PORTS);
}
pGDI->Hw.MPU401.PortBase = NULL;
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
return STATUS_SUCCESS;
}
BOOLEAN
SoundSetMPU401UARTMode(
IN PSOUND_HARDWARE pHw
)
{
int i;
PUCHAR MPU401PortBase;
MPU401PortBase = pHw->MPU401.PortBase;
/*
** Start UART mode - the ISR shuld catch the ack data byte
*/
if (!MPU401Write(MPU401PortBase, TRUE, MPU401_CMD_UART)) {
return FALSE;
}
return TRUE;
}
BOOLEAN
SoundMPU401Valid(PSOUND_HARDWARE pHw)
{
int i;
PUCHAR MPU401PortBase;
MPU401PortBase = pHw->MPU401.PortBase;
/*
** Check it's likely to be an MPU401
*/
if ((UCHAR)(READ_PORT_UCHAR(MPU401PortBase + MPU401_REG_STATUS) &
~(MPU401_DSR | MPU401_DRR)) !=
(UCHAR)~(MPU401_DSR | MPU401_DRR)) {
dprintf1(("Not MPU401"));
return FALSE;
}
/*
** Toss any input data
*/
for (i = 0; i < 3000; i++) {
READ_PORT_UCHAR(MPU401PortBase + MPU401_REG_DATA);
if (!(READ_PORT_UCHAR(MPU401PortBase + MPU401_REG_STATUS) & MPU401_DSR)) {
KeStallExecutionProcessor(1);
} else {
break;
}
}
/*
** Reset it - note it can get 'jammed' so just reset it anyway!
*/
if (!MPU401Write(MPU401PortBase, TRUE, MPU401_CMD_RESET)) {
WRITE_PORT_UCHAR(MPU401PortBase + MPU401_REG_COMMAND, MPU401_CMD_RESET);
}
/*
** Wait for ready
*/
for (i = 0; ; i++) {
if (!(READ_PORT_UCHAR(MPU401PortBase + MPU401_REG_STATUS) & MPU401_DSR)) {
break;
}
KeStallExecutionProcessor(25);
if (i > 10000) {
#if 0
//
// We may not get DSR - the following sequence fails to
// produce it:
//
// Reset
// Set UART Mode
// Reset (but don't read byte)
// Reset
//
dprintf1(("MPU401 timeout out waiting for ready after reset - port %X", MPU401PortBase));
dprintf1(("Status port is now %2.2X",
READ_PORT_UCHAR(MPU401PortBase + MPU401_REG_STATUS)));
#endif // 0
break;
}
}
/*
** Check data
*/
{
UCHAR Data;
Data = READ_PORT_UCHAR(MPU401PortBase + MPU401_REG_DATA);
if (Data != 0xFE) {
dprintf3(("MPU401 Read %2.2X, should have been 0xFE"));
return FALSE;
}
}
return TRUE;
}
#ifdef SB_CD
BOOLEAN
SoundCheckForSBCD(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN ULONG Port
)
/*++
Routine Description
See if our Sound Blaster 2 is a sound blaster 2 CD
--*/
{
PUCHAR SBCDBase;
ULONG PortToClaim;
NTSTATUS Status;
UCHAR SelectReg;
UCHAR DataReg;
PortToClaim = Port + MIX_ADDR_PORT; // Don't claim the CD control portion
//
// Check we're going to be allowed to use this port or whether
// some other device thinks it owns this hardware
//
Status = SoundReportResourceUsage(
pGDI->DeviceObject[WaveOutDevice], // Keep this
pGDI->BusType,
pGDI->BusNumber,
NULL,
0,
FALSE,
NULL,
&PortToClaim,
2);
if (!NT_SUCCESS(Status)) {
pGDI->LoadStatus = SOUND_CONFIG_PORT_INUSE;
return FALSE;
}
//
// Find where our device is mapped
//
SBCDBase = SoundMapPortAddress(
pGDI->BusType,
pGDI->BusNumber,
Port,
6,
&pGDI->MemType);
/*
** The register select port is write only
*/
SelectReg = READ_PORT_UCHAR(SBCDBase + MIX_ADDR_PORT);
if (SelectReg != 0xFF) {
if (pGDI->MemType == 0) {
MmUnmapIoSpace(SBCDBase, 6);
}
return FALSE;
}
/*
** Reset - any value will do so try to avoid mishaps by writing
** the value we read.
*/
WRITE_PORT_UCHAR(SBCDBase + MIX_ADDR_PORT, 0);
WRITE_PORT_UCHAR(SBCDBase + MIX_DATA_PORT,
READ_PORT_UCHAR(SBCDBase + MIX_DATA_PORT));
/*
** Select the master volume and read it
*/
WRITE_PORT_UCHAR(SBCDBase + MIX_ADDR_PORT, 2);
DataReg = READ_PORT_UCHAR(SBCDBase + MIX_DATA_PORT);
/*
** Default master volume is 4 (in bits 1 and 2)
*/
if (DataReg != 0x08 | 0xF1) {
/*
** Try to restore gracefully!
*/
WRITE_PORT_UCHAR(SBCDBase + MIX_ADDR_PORT, 0xFF);
if (pGDI->MemType == 0) {
MmUnmapIoSpace(SBCDBase, 6);
}
return FALSE;
}
/*
** Now look at the CD volume
*/
WRITE_PORT_UCHAR(SBCDBase + MIX_ADDR_PORT, 0x08);
DataReg = READ_PORT_UCHAR(SBCDBase + MIX_DATA_PORT);
/*
** Default CD volume is 0 (!)
*/
if (DataReg != 0xF1) {
/*
** Try to restore gracefully!
*/
WRITE_PORT_UCHAR(SBCDBase + MIX_ADDR_PORT, 0xFF);
if (pGDI->MemType == 0) {
MmUnmapIoSpace(SBCDBase, 6);
}
return FALSE;
}
pGDI->Hw.SBCDBase = SBCDBase;
return TRUE;
}
#endif // SB_CD
NTSTATUS
SoundInitIoPort(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PSB_CONFIG_DATA ConfigData
)
{
NTSTATUS Status;
ULONG PortToReport;
PortToReport =
//
// Check we're going to be allowed to use this port or whether
// some other device thinks it owns this hardware.
// We don't grab the synth stuff because the synth driver might
// want to grab it.
//
PortToReport = ConfigData->Port + MIX_ADDR_PORT;
Status = SoundReportResourceUsage(
pGDI->DeviceObject[WaveInDevice], // As good as any device to own
// it
pGDI->BusType,
pGDI->BusNumber,
NULL,
0,
FALSE,
NULL,
&PortToReport,
NUMBER_OF_SOUND_PORTS - MIX_ADDR_PORT);
if (!NT_SUCCESS(Status)) {
pGDI->LoadStatus = SOUND_CONFIG_PORT_INUSE;
return Status;
}
//
// Find where our device is mapped
//
pGDI->Hw.PortBase = SoundMapPortAddress(
pGDI->BusType,
pGDI->BusNumber,
ConfigData->Port,
NUMBER_OF_SOUND_PORTS,
&pGDI->MemType);
//
// Check no other SB card has this IO port. NOTE that unfortunately
// IoReportResourceUsage won't give us a conflict here for some
// reason
//
{
PGLOBAL_DEVICE_INFO pGDISearch;
for (pGDISearch = pGDI->Next; pGDISearch != pGDI;
pGDISearch = pGDISearch->Next) {
if (pGDISearch->Hw.PortBase == pGDI->Hw.PortBase) {
pGDI->LoadStatus = SOUND_CONFIG_PORT_INUSE;
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
}
}
//
// 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)) {
pGDI->Hw.DSPVersion = 0;
pGDI->LoadStatus = SOUND_CONFIG_BADPORT;
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
pGDI->Hw.DSPVersion = dspGetVersion(&pGDI->Hw);
//
// Save the version number in the registry
//
SoundWriteRegistryDWORD(pGDI->RegistryPathName,
SOUND_REG_DSP_VERSION,
pGDI->Hw.DSPVersion);
//
// Check for Thunderboards and spectrums
//
if (SB2(&pGDI->Hw) && dspGetVersion(&pGDI->Hw) != pGDI->Hw.DSPVersion) {
pGDI->LoadStatus = SOUND_CONFIG_THUNDER;
pGDI->Hw.ThunderBoard = TRUE;
}
#ifdef SB_CD
//
// If it's a 2.0 check for the SBCD stuff
//
if (SB201(&pGDI->Hw)) {
if (!SoundCheckForSBCD(pGDI, 0x250)) {
SoundCheckForSBCD(pGDI, 0x260);
}
}
#endif // SB_CD
//
// Check the version
//
if (pGDI->Hw.DSPVersion >= MIN_DSP_VERSION) {
#if 0
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 {
if (!SB16(&pGDI->Hw)) {
pGDI->MaxInHz = 23000;
pGDI->MaxOutHz = 23000;
} else {
pGDI->MinHz = 5000;
pGDI->MaxInHz = 44100;
pGDI->MaxOutHz = 44100;
}
}
}
#endif // 0
return STATUS_SUCCESS;
} else {
pGDI->LoadStatus = SOUND_CONFIG_BADPORT;
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
}
NTSTATUS
SoundInitDmaChannel(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PSB_CONFIG_DATA ConfigData
)
{
NTSTATUS Status;
DEVICE_DESCRIPTION DeviceDescription; // DMA adapter object
//
// Initialize status
//
pGDI->LoadStatus = SOUND_CONFIG_BADDMA;
//
// Check the channel id
//
switch (ConfigData->DmaChannel) {
case 0:
case 1:
case 3:
break;
default:
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
if (SB16(&pGDI->Hw)) {
switch (ConfigData->DmaChannel16) {
case 5:
case 6:
case 7:
case 0xFFFFFFFF: // Don't use 16-bit
break;
default:
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
}
//
// Check no other SB card has this IO port. NOTE that unfortunately
// IoReportResourceUsage won't give us a conflict here for some
// reason
//
{
PGLOBAL_DEVICE_INFO pGDISearch;
for (pGDISearch = pGDI->Next; pGDISearch != pGDI;
pGDISearch = pGDISearch->Next) {
if (pGDISearch->DmaChannel == ConfigData->DmaChannel ||
SB16(&pGDI->Hw) &&
ConfigData->DmaChannel16 != 0xFFFFFFFF &&
pGDISearch->DmaChannel16 == ConfigData->DmaChannel16) {
pGDI->LoadStatus = SOUND_CONFIG_PORT_INUSE;
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
}
}
//
// Check we're going to be allowed to use this DmaChannel or whether
// some other device thinks it owns this hardware
//
Status = SoundReportResourceUsage(
pGDI->DeviceObject[WaveInDevice], // As good as any device to own
// it
pGDI->BusType,
pGDI->BusNumber,
NULL,
0,
FALSE,
&ConfigData->DmaChannel,
NULL,
0);
if (!NT_SUCCESS(Status)) {
pGDI->LoadStatus = SOUND_CONFIG_DMA_INUSE;
return Status;
}
//
// Check the other channel (for SB16)
//
if (SB16(&pGDI->Hw)) {
if (ConfigData->DmaChannel16 != 0xFFFFFFFF) {
//
// Check we're going to be allowed to use this DmaChannel or whether
// some other device thinks it owns this hardware
//
Status = SoundReportResourceUsage(
pGDI->DeviceObject[WaveOutDevice], // KEEP this one!
pGDI->BusType,
pGDI->BusNumber,
NULL,
0,
FALSE,
&ConfigData->DmaChannel16,
NULL,
0);
if (!NT_SUCCESS(Status)) {
pGDI->LoadStatus = SOUND_CONFIG_DMA_INUSE;
return Status;
}
}
//
// If everything is OK - set it in the hardware
// (Don't use dspMixerWrite - it needs the mixer set
// up!
//
OUTPORT(&pGDI->Hw, MIX_ADDR_PORT, MIX_DMA_SELECT_REG);
OUTPORT(&pGDI->Hw, MIX_DATA_PORT,
ConfigData->DmaChannel16 == 0xFFFFFFFF ?
(UCHAR)(1 << ConfigData->DmaChannel) :
(UCHAR)((1 << ConfigData->DmaChannel) +
(1 << ConfigData->DmaChannel16)));
pGDI->DmaChannel16 = ConfigData->DmaChannel16;
} else {
// Test DMA for sbpro/2?
}
pGDI->DmaChannel = ConfigData->DmaChannel;
//
// Zero the device description structure.
//
RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
//
// Get the adapter object for this card.
//
DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
DeviceDescription.AutoInitialize = TRUE;
DeviceDescription.DemandMode = FALSE;
DeviceDescription.ScatterGather = FALSE;
DeviceDescription.InterfaceType = (pGDI->BusType == MicroChannel) ?
MicroChannel : Isa;
DeviceDescription.DmaSpeed = Compatible;
DeviceDescription.MaximumLength = ConfigData->DmaBufferSize;
DeviceDescription.BusNumber = pGDI->BusNumber;
if (SB16(&pGDI->Hw) && ConfigData->DmaChannel16 != 0xFFFFFFFF) {
ULONG NumberOfMapRegisters;
//
// Get our 16-bit adapter first
//
DeviceDescription.DmaWidth = Width16Bits;
DeviceDescription.DmaChannel = ConfigData->DmaChannel16;
pGDI->Adapter[1] = HalGetAdapter(&DeviceDescription,
&NumberOfMapRegisters);
//
// Check we got a good adapter and enough registers
//
if (pGDI->Adapter[1] == NULL) {
dprintf1(("Could not find adapter 16"));
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
if (NumberOfMapRegisters < BYTES_TO_PAGES(ConfigData->DmaBufferSize)) {
dprintf1(("Could only get %u mapping registers for DMA buffer",
NumberOfMapRegisters));
if (NumberOfMapRegisters == 0) {
return STATUS_INSUFFICIENT_RESOURCES;
}
ConfigData->DmaBufferSize = NumberOfMapRegisters * PAGE_SIZE;
}
}
DeviceDescription.DmaWidth = Width8Bits;
DeviceDescription.DmaChannel = ConfigData->DmaChannel;
Status = SoundGetCommonBuffer(&DeviceDescription, &pGDI->WaveInfo.DMABuf);
pGDI->Adapter[0] = pGDI->WaveInfo.DMABuf.AdapterObject[0];
return Status;
}
NTSTATUS
SoundInitInterrupt(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PSB_CONFIG_DATA ConfigData
)
{
NTSTATUS Status;
UCHAR InterruptSelect;
pGDI->LoadStatus = SOUND_CONFIG_BADINT;
//
// Check for invalid interrupt number
//
switch (ConfigData->InterruptNumber) {
case 9:
InterruptSelect = 0x01;
break;
case 3:
if (SB16(&pGDI->Hw)) {
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
case 5:
InterruptSelect = 0x02;
break;
case 7:
InterruptSelect = 0x04;
break;
case 10:
InterruptSelect = 0x08;
break;
default:
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
//
// Check we're going to be allowed to use this Interrupt or whether
// some other device thinks it owns this hardware
//
Status = SoundReportResourceUsage(
pGDI->DeviceObject[WaveInDevice], // As good as any device to own
// it
pGDI->BusType,
pGDI->BusNumber,
&ConfigData->InterruptNumber,
INTERRUPT_MODE,
(BOOLEAN)(SB16(&pGDI->Hw) ? TRUE : FALSE), // Sharable for SB16
NULL,
NULL,
0);
if (!NT_SUCCESS(Status)) {
pGDI->LoadStatus = SOUND_CONFIG_INT_INUSE;
return Status;
}
//
// See if we can get this interrupt.
// This test SHOULD detect conflict with multiple SB cards
// since we're saying the interrupt is not shared.
//
Status = SoundConnectInterrupt(
ConfigData->InterruptNumber,
pGDI->BusType,
pGDI->BusNumber,
SoundISR,
(PVOID)pGDI,
INTERRUPT_MODE,
(BOOLEAN)(SB16(&pGDI->Hw) ? TRUE : FALSE), // Sharable for SB16
&pGDI->WaveInfo.Interrupt);
if (!NT_SUCCESS(Status)) {
pGDI->LoadStatus = SOUND_CONFIG_INT_INUSE;
return Status;
}
//
// For the SB16 select the interrupt
//
if (SB16(&pGDI->Hw)) {
OUTPORT(&pGDI->Hw, MIX_ADDR_PORT, MIX_INTERRUPT_SELECT_REG);
OUTPORT(&pGDI->Hw, MIX_DATA_PORT, InterruptSelect);
}
//
// 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"));
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
}
}
return STATUS_SUCCESS;
}
NTSTATUS
SoundSaveConfig(
IN PWSTR RegistryPath,
IN ULONG Port,
IN ULONG DmaChannel,
IN ULONG DmaChannel16,
IN ULONG Interrupt,
IN ULONG MPU401Port,
IN BOOLEAN HaveSynth,
IN BOOLEAN SynthIsOpl3,
IN ULONG DmaBufferSize
)
{
NTSTATUS Status;
Status = SoundWriteRegistryDWORD(RegistryPath, SOUND_REG_PORT, Port);
if (!NT_SUCCESS(Status)) {
return Status;
}
Status = SoundWriteRegistryDWORD(RegistryPath, SOUND_REG_DMACHANNEL, DmaChannel);
if (!NT_SUCCESS(Status)) {
return Status;
}
Status = SoundWriteRegistryDWORD(RegistryPath, SOUND_REG_DMACHANNEL16, DmaChannel16);
if (!NT_SUCCESS(Status)) {
return Status;
}
Status = SoundWriteRegistryDWORD(RegistryPath, SOUND_REG_INTERRUPT, Interrupt);
if (!NT_SUCCESS(Status)) {
return Status;
}
Status = SoundWriteRegistryDWORD(RegistryPath, SOUND_REG_MPU401_PORT, MPU401Port);
if (!NT_SUCCESS(Status)) {
return Status;
}
Status = SoundWriteRegistryDWORD(RegistryPath, SOUND_REG_REALBUFFERSIZE, DmaBufferSize);
if (!NT_SUCCESS(Status)) {
return Status;
}
if (HaveSynth) {
Status = SoundWriteRegistryDWORD(RegistryPath, SOUND_REG_SYNTH_TYPE,
SynthIsOpl3 ? SOUND_SYNTH_TYPE_OPL3 :
SOUND_SYNTH_TYPE_ADLIB);
if (!NT_SUCCESS(Status)) {
return Status;
}
}
return STATUS_SUCCESS;
}
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));
}
if (_wcsicmp(ValueName, SOUND_REG_MPU401_PORT) == 0) {
ConfigData->MPU401Port = *(PULONG)ValueData;
dprintf3(("Read MPU401 Port Base : %x", ConfigData->MPU401Port));
}
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_DMACHANNEL16) == 0) {
ConfigData->DmaChannel16 = *(PULONG)ValueData;
dprintf3(("Read 16-bit DMA Channel : %x", ConfigData->DmaChannel16));
}
else if (_wcsicmp(ValueName, SOUND_REG_DMABUFFERSIZE) == 0) {
ConfigData->DmaBufferSize = *(PULONG)ValueData;
dprintf3(("Read Buffer size : %x", ConfigData->DmaBufferSize));
}
else if (_wcsicmp(ValueName, SOUND_REG_LOADTYPE) == 0) {
ConfigData->LoadType = *(PULONG)ValueData;
dprintf3(("LoadType : %x", ConfigData->LoadType));
}
} else {
if (ValueType == REG_BINARY &&
_wcsicmp(ValueName, SOUND_MIXER_SETTINGS_NAME) == 0) {
if (ValueLength <= sizeof(ConfigData->MixerSettings)) {
dprintf3(("Mixer settings"));
RtlCopyMemory((PVOID)&ConfigData->MixerSettings,
ValueData,
ValueLength);
ConfigData->MixerSettingsFound = TRUE;
} else {
dprintf1(("Mixer settings too big - expected <= %x, got %x",
sizeof(ConfigData->MixerSettings), ValueLength));
}
}
}
return STATUS_SUCCESS;
}