void get_write_paddings(unsigned long addr, int *p1, int *p2, int *p3, int *p4, int bytes_written) { // greetings to scud :-) int write_byte; int already_written; int padding; write_byte=SB1(addr); already_written=bytes_written; write_byte+=0x100; already_written%=0x100; padding=(write_byte-already_written)%0x100; if(padding<10) padding+=0x100; *p1=padding; write_byte=SB2(addr); already_written+=padding; write_byte+=0x100; already_written%=0x100; padding=(write_byte-already_written)%0x100; if(padding<10) padding+=0x100; *p2=padding; write_byte=SB3(addr); already_written+=padding; write_byte+=0x100; already_written%=0x100; padding=(write_byte-already_written)%0x100; if(padding<10) padding+=0x100; *p3=padding; write_byte=SB4(addr); already_written+=padding; write_byte+=0x100; already_written%=0x100; padding=(write_byte-already_written)%0x100; if(padding<10) padding+=0x100; *p4=padding; }
NTSTATUS SoundCardInstanceInit( IN PWSTR RegistryPathName, IN PVOID Context ) { /* ** Instance data */ PSOUND_CARD_INSTANCE CardInstance; // // Return code from last function called // NTSTATUS Status; // // Configuration data : // SB_CONFIG_DATA ConfigData; // // Where we keep all general driver information // We avoid using static data because : // 1. Accesses are slower with 32-bit offsets // 2. We support more than one card instance // PGLOBAL_DEVICE_INFO pGDI; // // The number of devices we actually create // int NumberOfDevicesCreated; // // The context is the global device info pointer from the previous // instance // CardInstance = Context; /******************************************************************** * * Allocate our global info * ********************************************************************/ pGDI = (PGLOBAL_DEVICE_INFO)ExAllocatePool( NonPagedPool, sizeof(GLOBAL_DEVICE_INFO)); if (pGDI == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } dprintf4((" DriverEntry(): GlobalInfo : %08lXH", pGDI)); RtlZeroMemory(pGDI, sizeof(GLOBAL_DEVICE_INFO)); pGDI->Key = GDI_KEY; pGDI->Hw.Key = HARDWARE_KEY; pGDI->RegistryPathName = RegistryPathName; pGDI->Usage = 0xFF; // Free pGDI->DriverObject = CardInstance->pDriverObject; // // Mutual exclusion : // // Everything is synchronized on the DeviceMutex (except for // some stuff inside the wave device) except // // Midi external output which takes too long and so is synchronized // separately but grabs the DeviceMutex every time it actually // writes anything and // // Synth output where the hardware is separate but callbacks to the // mixer must grab the DeviceMutex. // KeInitializeMutex(&pGDI->DeviceMutex, 2 // High level ); KeInitializeMutex(&pGDI->MidiMutex, 1 // Low level ); KeInitializeMutex(&pGDI->Hw.DSPMutex, 3 // Highest level ); /******************************************************************** * * Add ourselves to the ring of cards * ********************************************************************/ if (CardInstance->PrevGDI == NULL) { pGDI->Next = pGDI; } else { PGLOBAL_DEVICE_INFO pNext; pNext = CardInstance->PrevGDI->Next; CardInstance->PrevGDI->Next = pGDI; pGDI->Next = pNext; } CardInstance->PrevGDI = pGDI; /******************************************************************** * * See if we can find our bus. We run on both ISA and EISA * We ASSUME that if there's an ISA bus we're on that * ********************************************************************/ Status = SoundGetBusNumber(Isa, &pGDI->BusNumber); if (!NT_SUCCESS(Status)) { // // Cound not find an ISA bus so try EISA // Status = SoundGetBusNumber(Eisa, &pGDI->BusNumber); if (!NT_SUCCESS(Status)) { Status = SoundGetBusNumber(MicroChannel, &pGDI->BusNumber); if (!NT_SUCCESS(Status)) { dprintf1(("driver does not work on non-Isa/Eisa/Mca")); return Status; } pGDI->BusType = MicroChannel; } else { pGDI->BusType = Eisa; } } else { pGDI->BusType = Isa; } // // Set configuration to default in case we don't get all the // values back from the registry. // // Also set default volume for all devices // ConfigData.Port = SOUND_DEF_PORT; ConfigData.InterruptNumber = SOUND_DEF_INT; ConfigData.DmaChannel = SOUND_DEF_DMACHANNEL; ConfigData.DmaChannel16 = SOUND_DEF_DMACHANNEL16; ConfigData.DmaBufferSize = DEFAULT_DMA_BUFFERSIZE; ConfigData.MPU401Port = SOUND_DEF_MPU401_PORT; ConfigData.LoadType = SOUND_LOADTYPE_NORMAL; ConfigData.MixerSettingsFound = FALSE; // // Get the system configuration information for this driver. // // // Port, Interrupt, DMA channel, DMA 16-bit channel DMA buffer size // { RTL_QUERY_REGISTRY_TABLE Table[2]; RtlZeroMemory(Table, sizeof(Table)); Table[0].QueryRoutine = SoundReadConfiguration; Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, pGDI->RegistryPathName, Table, &ConfigData, NULL ); if (!NT_SUCCESS(Status)) { dprintf1(("ERROR: DriverEntry(): RtlQueryRegistryValues() Failed with Status = %XH", Status)); return Status; } // End IF (!NT_SUCCESS(Status)) } // End Query Resistry Values // // Save additional Config data // pGDI->InterruptNumber = ConfigData.InterruptNumber; pGDI->DmaChannel = ConfigData.DmaChannel; pGDI->DmaChannel16 = ConfigData.DmaChannel16; // // Verify the DMA Buffer Size // if ( ConfigData.DmaBufferSize < MIN_DMA_BUFFERSIZE ) { ConfigData.DmaBufferSize = MIN_DMA_BUFFERSIZE; dprintf1((" DriverEntry(): Adjusting the DMA Buffer size, size in Registry was too small")); } // // print out some info about the configuration // dprintf2((" DriverEntry(): Base I/O Port = %XH", ConfigData.Port)); dprintf2((" DriverEntry(): Interrupt = %u", ConfigData.InterruptNumber)); dprintf2((" DriverEntry(): DMA Channel = %u", ConfigData.DmaChannel)); dprintf2((" DriverEntry(): DMA Channel (16 bit) = %u", ConfigData.DmaChannel16)); dprintf2((" DriverEntry(): DMA Buffer Size = %XH", ConfigData.DmaBufferSize)); dprintf2((" DriverEntry(): MPU 401 port = %XH", ConfigData.MPU401Port)); /* ** Create our wave devices to ease reporting problems */ Status = SBCreateDevice(pGDI, WaveInDevice); if (!NT_SUCCESS(Status)) { return Status; } Status = SBCreateDevice(pGDI, WaveOutDevice); if (!NT_SUCCESS(Status)) { return Status; } /* ** Say we want to be called at shutdown time */ Status = IoRegisterShutdownNotification(pGDI->DeviceObject[WaveInDevice]); if (!NT_SUCCESS(Status)) { return Status; } pGDI->ShutdownRegistered = TRUE; /* ** Check the configuration and acquire the resources */ Status = SoundInitHardwareConfig(pGDI, &ConfigData); if (!NT_SUCCESS(Status)) { dprintf1(("ERROR: DriverEntry(): SoundInitHardwareConfig() Failed with Status = %XH", Status)); return Status; } /* ** Initialize generic device environments - first get the ** hardware routines in place. ** We do this here after we've found out what hardware we've got */ HwInitialize(pGDI); SoundInitMidiIn(&pGDI->MidiInfo, &pGDI->Hw); /* ** Register most of our resources. Some may be registered on ** the wave output device : ** 16-bit dma channel ** ** We wipe out the registration of the MPU401 port when we do this ** but this is OK. */ { ULONG PortToReport; PortToReport = ConfigData.Port + MIX_ADDR_PORT; 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 &ConfigData.DmaChannel, &PortToReport, NUMBER_OF_SOUND_PORTS - MIX_ADDR_PORT); } if (!NT_SUCCESS(Status)) { dprintf1(("Error - failed to claim resources - code %8X", Status)); pGDI->LoadStatus = SOUND_CONFIG_ERROR; return Status; } /* ** Now we know what device we've got we can create the appropriate ** devices */ /* ** Thuderboard has no external midi and we're going to ** drive the SB16 in MPU401 mode if we can */ if (!pGDI->Hw.ThunderBoard) { // // Don't create the MPU401 device if it is disabled // if (!SB16(&pGDI->Hw) || (ULONG)-1 != ConfigData.MPU401Port) { Status = SBCreateDevice(pGDI, MidiOutDevice); if (!NT_SUCCESS(Status)) { return Status; } Status = SBCreateDevice(pGDI, MidiInDevice); if (!NT_SUCCESS(Status)) { return Status; } } } /* ** Create volume control stuff for those devices which have it */ if (SBPRO(&pGDI->Hw) || SB16(&pGDI->Hw) #ifdef SB_CD || pGDI->Hw.SBCDBase != NULL #endif // SB_CD ) { Status = SBCreateDevice(pGDI, LineInDevice); if (!NT_SUCCESS(Status)) { return Status; } Status = SBCreateDevice(pGDI, CDInternal); if (!NT_SUCCESS(Status)) { return Status; } Status = SBCreateDevice(pGDI, MixerDevice); if (!NT_SUCCESS(Status)) { return Status; } } else { /* Volume setting not supported for our wave device */ ((PLOCAL_DEVICE_INFO)pGDI->DeviceObject[WaveOutDevice]->DeviceExtension)->CreationFlags |= SOUND_CREATION_NO_VOLUME; } /* ** Init the WaveInfo structure */ SoundInitializeWaveInfo(&pGDI->WaveInfo, (UCHAR)(SB1(&pGDI->Hw) ? SoundReprogramOnInterruptDMA : SoundAutoInitDMA), SoundQueryFormat, &pGDI->Hw); if (ConfigData.SynthType == SOUND_SYNTH_TYPE_NONE) { /* ** This will happen if the user selected a basic config without ** a synthesizer. */ dprintf2(("No synth!")); } else { Status = SynthInit(CardInstance->pDriverObject, pGDI->RegistryPathName, &pGDI->Synth, SB16(&pGDI->Hw) || SBPRO(&pGDI->Hw) && INPORT(&pGDI->Hw, 0) == 0 ? ConfigData.Port : SYNTH_PORT, FALSE, // Interrupt not enabled pGDI->BusType, pGDI->BusNumber, NULL, SOUND_MIXER_INVALID_CONTROL_ID,// Set volume later TRUE, // Allow multiple SoundMidiOutGetSynthCaps ); if (!NT_SUCCESS(Status)) { /* ** OK - we can get along without a synth */ dprintf2(("No synth!")); } else { if (!pGDI->Synth.IsOpl3) { dprintf2(("Synth is Adlib")); } else { /* ** Bad aliasing in early sound blasters means we can ** guess wrong. */ if (!(SB16(&pGDI->Hw) || SBPRO(&pGDI->Hw) && INPORT(&pGDI->Hw, 0) == 0)) { pGDI->Synth.IsOpl3 = FALSE; } dprintf2(("Synth is Opl3")); } } } /* ** Set the mixer up. ** ** Note that the mixer info depends on what hardware is present ** so this must be called after we have checked out the hardware. */ if (pGDI->DeviceObject[MixerDevice]) { Status = SoundMixerInit(pGDI->DeviceObject[MixerDevice]->DeviceExtension, &ConfigData.MixerSettings, ConfigData.MixerSettingsFound); if (!NT_SUCCESS(Status)) { return Status; } } /* ** Save new settings */ Status = SoundSaveConfig(pGDI->RegistryPathName, ConfigData.Port, ConfigData.DmaChannel, ConfigData.DmaChannel16, ConfigData.InterruptNumber, ConfigData.MPU401Port, (BOOLEAN)(pGDI->Synth.DeviceObject != NULL), pGDI->Synth.IsOpl3, pGDI->WaveInfo.DMABuf.BufferSize); if (!NT_SUCCESS(Status)) { return Status; } /* ** Finally test the PRO interrupt */ if (SBPRO(&pGDI->Hw)) { BOOLEAN Ok; SoundEnter(pGDI->DeviceObject[WaveOutDevice]->DeviceExtension, TRUE); Ok = 0 == SoundTestWaveDevice(pGDI->DeviceObject[WaveOutDevice]); SoundEnter(pGDI->DeviceObject[WaveOutDevice]->DeviceExtension, FALSE); if (!Ok) { pGDI->LoadStatus = SOUND_CONFIG_BADDMA; return STATUS_DEVICE_CONFIGURATION_ERROR; } } /* ** Exit OK Message */ pGDI->LoadStatus = SOUND_CONFIG_OK; return STATUS_SUCCESS; }
NTSTATUS SoundMixerInit( PLOCAL_DEVICE_INFO pLDI, PMIXER_REGISTRY_DATA SavedControlData, BOOLEAN MixerSettingsFound ) { int i, SetIndex; PLOCAL_MIXER_DATA LocalMixerData; PGLOBAL_DEVICE_INFO pGDI; PMIXER_INFO MixerInfo; pGDI = pLDI->pGlobalInfo; MixerInfo = &pGDI->MixerInfo; LocalMixerData = &pGDI->LocalMixerData; /* ** Avoid assertions by properly entering the mixer */ /* ** Pick up the correct mixer type */ if (SB1(&pGDI->Hw)) { return STATUS_SUCCESS; } KeWaitForSingleObject(&pGDI->DeviceMutex, Executive, KernelMode, FALSE, // Not alertable NULL); #ifdef SB_CD if (pGDI->Hw.SBCDBase) { SBCDMixerInit(pGDI); } else #endif // SB_CD { if (SBPRO(&pGDI->Hw)) { SBPROMixerInit(pGDI); } else { ASSERT(SB16(&pGDI->Hw)); SB16MixerInit(pGDI); } } ASSERT(LocalMixerData->NumberOfControls <= MAXCONTROLS); ASSERT(LocalMixerData->NumberOfLines <= MAXLINES); ASSERT(LocalMixerData->MaxSettableItems <= MAXSETTABLECONTROLS); /* ** Check the saved data matches */ if (MixerSettingsFound) { dprintf3(("Saved mixer settings: Version = %x, DSPVersion = %x, NumberOfControls = %d", SavedControlData->MixerVersion, SavedControlData->DSPVersion, SavedControlData->NumberOfControls)); if (SavedControlData->MixerVersion != DRIVER_VERSION || SavedControlData->DSPVersion != pGDI->Hw.DSPVersion || SavedControlData->NumberOfControls != LocalMixerData->MaxSettableItems) { dprintf1(("Saved mixer settings incompatible")); MixerSettingsFound = FALSE; } } /* ** Init the generic mixer stuff first so we can use it */ SoundInitMixerInfo(&pGDI->MixerInfo, HwGetLineFlags, HwGetControl, HwGetCombinedControl, HwSetControl); /* ** Get to a known state - this is common to ALL mixers ** Detecting the SBCD mixer involves resetting it however. */ #ifdef SB_CD if (pGDI->Hw.SBCDBase == NULL) { dspWriteMixer(pGDI, MIX_RESET_REG, 0); } #endif // SB_CD /* ** Set this device up with its mixer data */ pLDI->DeviceType = MIXER_DEVICE; pLDI->DeviceSpecificData = (PVOID)MixerInfo; /* ** Make sure everyone can find the mixer device */ { PDEVICE_OBJECT pDO; PLOCAL_DEVICE_INFO pLDIDev; for (pDO = pGDI->DeviceObject[WaveInDevice]->DriverObject->DeviceObject; pDO != NULL; pDO = pDO->NextDevice) { pLDIDev = (PLOCAL_DEVICE_INFO)pDO->DeviceExtension; /* ** For multiple cards the following test may fail */ if (pLDIDev->pGlobalInfo == pGDI || pDO == pGDI->Synth.DeviceObject) { pLDIDev->MixerDevice = pLDI; } } } /* ** Create control info */ for (i = 0, SetIndex = 0; i < LocalMixerData->NumberOfControls ; i++) { /* ** Read limits */ if ((LocalMixerData->MixerControlInit[i].dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_SIGNED) { pGDI->LocalMixerData.ControlInfo[i].Signed = TRUE; pGDI->LocalMixerData.ControlInfo[i].Range.Min.s = (SHORT)LocalMixerData->MixerControlInit[i].Bounds.lMinimum; pGDI->LocalMixerData.ControlInfo[i].Range.Max.s = (SHORT)LocalMixerData->MixerControlInit[i].Bounds.lMaximum; } else { if ((LocalMixerData->MixerControlInit[i].dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_BOOLEAN) { pGDI->LocalMixerData.ControlInfo[i].Boolean = TRUE; } pGDI->LocalMixerData.ControlInfo[i].Range.Min.u = (USHORT)LocalMixerData->MixerControlInit[i].Bounds.dwMinimum; pGDI->LocalMixerData.ControlInfo[i].Range.Max.u = (USHORT)LocalMixerData->MixerControlInit[i].Bounds.dwMaximum; } /* ** Remember if it's a mux and tot up text items */ if (LocalMixerData->MixerControlInit[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER || LocalMixerData->MixerControlInit[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX) { pGDI->LocalMixerData.ControlInfo[i].Mux = TRUE; LocalMixerData->NumberOfTextItems += (UCHAR)LocalMixerData->MixerControlInit[i].cMultipleItems; ASSERT(LocalMixerData->MixerControlInit[i].cMultipleItems <= MAXITEMS); } /* ** Only meters are not settable here */ if ((LocalMixerData->MixerControlInit[i].dwControlType & MIXERCONTROL_CT_CLASS_MASK) != MIXERCONTROL_CT_CLASS_METER) { LocalMixerData->ControlInfo[i].SetIndex = (UCHAR)SetIndex; SoundInitDataItem(MixerInfo, &LocalMixerData->ControlNotification[SetIndex], (USHORT)MM_MIXM_CONTROL_CHANGE, (USHORT)i); if (MixerSettingsFound) { /* ** What if it's invalid? */ LocalMixerData->ControlInfo[i].Data = SavedControlData->ControlData[SetIndex]; } SetIndex++; } else { LocalMixerData->ControlInfo[i].SetIndex = MIXER_SET_INDEX_INVALID; } } ASSERTMSG("MaxSettableItems wrong!", SetIndex == LocalMixerData->MaxSettableItems); /* ** Create line info */ for (i = 0; i < LocalMixerData->NumberOfLines; i++) { SoundInitDataItem(MixerInfo, &pGDI->LocalMixerData.LineNotification[i], (USHORT)MM_MIXM_LINE_CHANGE, (USHORT)i); } /* ** Set everything up. */ for (i = 0; i < LocalMixerData->NumberOfControls; i++) { SoundMixerSet(pGDI, i); } KeReleaseMutex(&pGDI->DeviceMutex, FALSE); return STATUS_SUCCESS; }