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.
 
 
 
 
 
 

885 lines
22 KiB

/*++
"@(#) NEC config.c 1.1 95/03/22 21:23:26"
Copyright (c) 1994 NEC Corporation
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.
Environment:
Kernel mode
Revision History:
--*/
#include "sound.h"
#include <string.h>
//
// Internal routines
//
NTSTATUS
SoundInitIoPort(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PULONG Port
);
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,
IN ULONG DmaBufferSize
);
NTSTATUS
SoundInitInterrupt(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PULONG Interrupt
);
NTSTATUS
SoundInterruptValid(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PULONG Interrupt
);
BOOLEAN
InList(
IN CONST ULONG * List,
IN ULONG Value
);
BOOLEAN
SoundTestTransfer(
IN PGLOBAL_DEVICE_INFO pGDI,
IN ULONG MajorFunction,
IN PDEVICE_OBJECT pDO,
IN PVOID DeviceData
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,SoundInitHardwareConfig)
#pragma alloc_text(INIT,SoundInitIoPort)
#pragma alloc_text(INIT,SoundPortValid)
#pragma alloc_text(INIT,SoundInitDmaChannel)
#pragma alloc_text(INIT,SoundDmaChannelValid)
#pragma alloc_text(INIT,SoundInitInterrupt)
#pragma alloc_text(INIT,SoundInterruptValid)
#pragma alloc_text(INIT,SoundSaveConfig)
#pragma alloc_text(INIT,InList)
#pragma alloc_text(INIT,SoundTestInterruptAndDMA)
#endif
NTSTATUS SoundInitHardwareConfig( IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PULONG Port,
IN OUT PULONG InterruptNumber,
IN OUT PULONG DmaChannel,
IN OUT PULONG InputSource,
IN ULONG DmaBufferSize )
{
NTSTATUS Status;
dprintf5(("SoundInitHardwareConfig(): Port = 0x%x", *Port));
dprintf5(("SoundInitHardwareConfig(): Interrupt = %d", *InterruptNumber));
dprintf5(("SoundInitHardwareConfig(): DMA Channel= %d", *DmaChannel));
dprintf5(("SoundInitHardwareConfig(): InputSource= %d", *InputSource));
dprintf5(("SoundInitHardwareConfig(): DmaBufSize = 0x%x", DmaBufferSize));
// Find port
Status = SoundInitIoPort(pGDI, Port);
if (!NT_SUCCESS(Status))
{
return Status;
}
dprintf5(("SoundInitIoPort() Success!! Port = 0x%x", *Port));
// Find interrupt
Status = SoundInitInterrupt(pGDI, InterruptNumber);
if (!NT_SUCCESS(Status))
{
return Status;
}
dprintf5(("SoundInitInterrupt() Success!! Int = %d", *InterruptNumber));
// Find DMA channel
Status = SoundInitDmaChannel(pGDI, DmaChannel, DmaBufferSize);
pGDI->DmaChannel = *DmaChannel;
if (!NT_SUCCESS(Status))
{
return Status;
}
dprintf5(("SoundInitDmaChannel() Success!! DMA chan = %d", *DmaChannel));
// Report all resources used
Status = SoundReportResourceUsage(pGDI->DeviceObject[WaveInDevice],
pGDI->BusType,
pGDI->BusNumber,
InterruptNumber, // Not use this value
INTERRUPT_MODE,
IRQ_SHARABLE,
DmaChannel,
Port,
NUMBER_OF_SOUND_PORTS);
if (!NT_SUCCESS(Status))
{
return Status;
}
dprintf5(("SoundReportResourceUsage() Success!!"));
// Check the input source
if (*InputSource > INPUT_OUTPUT)
{
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
// Now we know all our data we can set up the real hardware
// The global device info now contains all device mappings etc
if (!HwInitialize(&pGDI->WaveInfo,
&pGDI->Hw,
*DmaChannel,
*InterruptNumber,
*InputSource))
{
SoundSetErrorCode(pGDI->RegistryPathName, SOUND_CONFIG_BADCARD);
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
dprintf5(("HwInitialize() Success!!"));
return STATUS_SUCCESS;
}
BOOLEAN
InList(
IN CONST ULONG *List,
IN ULONG Value
)
{
for ( ; *List != 0xFFFF ; List++) { // 0xFFFF = end of list
if (Value == *List) {
return TRUE;
}
}
return FALSE;
}
NTSTATUS SoundInitIoPort( IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PULONG Port )
{
ULONG CurrentPort;
int i;
NTSTATUS Status;
static CONST ULONG PortChoices[] = VALID_IO_PORTS;
dprintf5((">>>> SoundInitIoPort(): Port = %8x", *Port));
Status = SoundPortValid(pGDI, Port);
if (NT_SUCCESS(Status))
{
return Status;
}
dprintf2(("No valid IO port found"));
SoundSetErrorCode(pGDI->RegistryPathName, SOUND_CONFIG_NOCARD);
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
NTSTATUS
SoundPortValid(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PULONG Port
)
{
NTSTATUS Status;
dprintf5((">>> SoundPortValid(): Port = %8x", *Port));
//
// 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,
Port,
NUMBER_OF_SOUND_PORTS);
if (!NT_SUCCESS(Status)) {
return Status;
}
dprintf5(("SoundReportResourceUsage() Success!!"));
//
// Find where our device is mapped
//
pGDI->Hw.PortBase = SoundMapPortAddress(
pGDI->BusType,
pGDI->BusNumber,
*Port,
NUMBER_OF_SOUND_PORTS,
&pGDI->MemType);
dprintf4(("Mapped PortBase = %8x", pGDI->Hw.PortBase));
//
// Finally we can check and see if the hardware is happy
//
if (HwIsIoValid(&pGDI->Hw)) {
dprintf5(("HwIsIoValid() Success!!"));
return STATUS_SUCCESS;
}
dprintf2(("HwIsIoValid() Faided!!"));
//
// Free any resources. (note we don't have to do
// IoReportResourceUsage again because each one overwrites the
// previous).
//
if (pGDI->MemType == 0) {
MmUnmapIoSpace(pGDI->Hw.PortBase, NUMBER_OF_SOUND_PORTS);
dprintf4(("Free IO space"));
}
pGDI->Hw.PortBase = NULL;
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
NTSTATUS
SoundInitDmaChannel(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PULONG DmaChannel,
IN ULONG DmaBufferSize
)
{
ULONG CurrentDmaChannel;
NTSTATUS Status;
int i;
static CONST ULONG DmaChannelChoices[] = VALID_DMA_CHANNELS;
Status = SoundDmaChannelValid(pGDI, DmaChannel, DmaBufferSize);
if (NT_SUCCESS(Status)) {
return Status;
}
dprintf2(("No valid DMA channel found"));
SoundSetErrorCode(pGDI->RegistryPathName, SOUND_CONFIG_BADDMA);
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
NTSTATUS
SoundDmaChannelValid(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PULONG DmaChannel,
IN ULONG DmaBufferSize
)
{
NTSTATUS Status;
DEVICE_DESCRIPTION DeviceDescription; // DMA adapter object
// See if the hardware is happy
//
if (!pGDI->Hw.NoPCR && !HwIsDMAValid(&pGDI->Hw, *DmaChannel)) {
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
dprintf5(("HwIsDMAValid() Success!!"));
//
// 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,
DmaChannel,
NULL,
0);
if (!NT_SUCCESS(Status)) {
return Status;
}
//
// 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 = FALSE;
DeviceDescription.DemandMode = !pGDI->SingleModeDMA;
DeviceDescription.ScatterGather = FALSE;
DeviceDescription.DmaChannel = *DmaChannel;
DeviceDescription.InterfaceType = pGDI->BusType;
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;
ULONG CurrentInterrupt;
int i;
static CONST ULONG InterruptChoices[] = VALID_INTERRUPTS;
Status = SoundInterruptValid(pGDI, Interrupt);
if (NT_SUCCESS(Status)) {
return Status;
}
dprintf2(("No valid Interrupt found"));
SoundSetErrorCode(pGDI->RegistryPathName, SOUND_CONFIG_BADINT);
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
NTSTATUS
SoundInterruptValid(
IN OUT PGLOBAL_DEVICE_INFO pGDI,
IN OUT PULONG Interrupt
)
{
NTSTATUS Status;
DEVICE_DESCRIPTION DeviceDescription; // DMA adapter object
//
// See if the hardware is happy
//
//if (!HwIsInterruptValid(&pGDI->Hw, *Interrupt)) {
// dprintf3(("HwIsInterruptValid() Failed"));
// 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,
Interrupt,
INTERRUPT_MODE,
IRQ_SHARABLE,
NULL,
NULL,
0);
if (!NT_SUCCESS(Status)) {
dprintf2(("SoundReportResourceUsage() Failed"));
return Status;
}
//
// See if we can get this interrupt
//
return SoundConnectInterrupt(
*Interrupt,
pGDI->BusType,
pGDI->BusNumber,
SoundISR,
(PVOID)pGDI,
INTERRUPT_MODE,
IRQ_SHARABLE,
&pGDI->WaveInfo.Interrupt);
}
NTSTATUS
SoundSaveConfig(
IN PWSTR RegistryPath,
IN ULONG Port,
IN ULONG DmaChannel,
IN ULONG Interrupt,
IN ULONG InputSource
)
{
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_INTERRUPT, Interrupt);
if (!NT_SUCCESS(Status)) {
return Status;
}
Status = SoundWriteRegistryDWORD(RegistryPath, SOUND_REG_INPUTSOURCE, InputSource);
if (!NT_SUCCESS(Status)) {
return Status;
}
}
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
--*/
{
PSOUND_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 : 0x%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 Buffer size : 0x%x", ConfigData->DmaBufferSize));
}
else if (_wcsicmp(ValueName, SOUND_REG_SINGLEMODEDMA) == 0) {
ConfigData->SingleModeDMA = *(PULONG)ValueData;
dprintf3(("Read DemandMode : %x", ConfigData->SingleModeDMA));
}
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 {
if (ValueType == REG_BINARY &&
_wcsicmp(ValueName, SOUND_MIXER_SETTINGS_NAME) == 0) {
ASSERTMSG("Mixer data wrong length!",
ValueLength == sizeof(ConfigData->MixerSettings));
dprintf3(("Mixer settings"));
RtlCopyMemory((PVOID)ConfigData->MixerSettings,
ValueData,
ValueLength);
ConfigData->MixerSettingsFound = TRUE;
}
}
return STATUS_SUCCESS;
}
NTSTATUS
SoundConfigCallBack(
IN PVOID Context,
IN PUNICODE_STRING PathName,
IN INTERFACE_TYPE BusType,
IN ULONG BusNumber,
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
IN CONFIGURATION_TYPE ControllerType,
IN ULONG ControllerNumber,
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
IN CONFIGURATION_TYPE PeripheralType,
IN ULONG PeripheralNumber,
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
)
/*++
Routine Description:
This routine is used to acquire all of the configuration
information for audio controller driver attached to that controller.
Arguments:
Context - Pointer to the confuration information we are building
up.
PathName - unicode registry path. Not Used.
BusType - Internal Only.
BusNumber - Which bus if we are on a multibus system.
BusInformation - Configuration information about the bus. Not Used.
ControllerType - Should always be AudioController.
ControllerNumber - Which controller if there is more than one
controller in the system.
ControllerInformation - Array of pointers to the three pieces of
registry information.
PeripheralType - not used.
PeripheralNumber - not used.
PeripheralInformation - not used.
Return Value:
STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
if all of the resource information couldn't be acquired.
--*/
{
PCM_FULL_RESOURCE_DESCRIPTOR controllerData;
//
// So we don't have to typecast the context.
//
PCONFIG_CONTROLLER_DATA controller = Context;
//
// Simple iteration variable.
//
ULONG i;
//
// These three boolean will tell us whether we got all the
// information that we needed.
//
BOOLEAN foundPort = FALSE;
BOOLEAN foundInterrupt = FALSE;
BOOLEAN foundDma = FALSE;
//ASSERT(ControllerType == AudioController);
//ASSERT(PeripheralType == AudioPeripheral);
//
// Check if the information from the registry for this device
// is valid.
//
if (!(((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) +
ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset)) {
ASSERT(FALSE);
return STATUS_INVALID_PARAMETER;
}
//
// Loop through the "slots" that we have for a new controller.
// Determine if this is a controller that we've already seen,
// or a new controller.
//
controllerData =
(PCM_FULL_RESOURCE_DESCRIPTOR)
(((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) +
ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset);
//
// We have the pointer. Save off the interface type and
// the busnumber for use when we call the Hal and the
// Io System.
//
controller->InterfaceType = BusType;
controller->BusNumber = BusNumber;
//
// Interrupt Vector that is for sound can not sharable.
//
controller->SharableVector = FALSE; /* Set False */ /* masao */
//
// We need to get the following information out of the partial
// resource descriptors.
//
// The irql and vector.
//
// The dma channel.
//
// The base address and span covered by the Audio controllers
// registers.
//
// It is not defined how these appear in the partial resource
// lists, so we will just loop over all of them. If we find
// something we don't recognize, we drop that information on
// the floor. When we have finished going through all the
// partial information, we validate that we got the above
// three.
//
for (
i = 0;
i < controllerData->PartialResourceList.Count;
i++
) {
PCM_PARTIAL_RESOURCE_DESCRIPTOR partial =
&controllerData->PartialResourceList.PartialDescriptors[i];
switch (partial->Type) {
case CmResourceTypePort: {
foundPort = TRUE;
//
// Save of the pointer to the partial so
// that we can later use it to report resources
// and we can also use this later in the routine
// to make sure that we got all of our resources.
//
controller->SpanOfControllerAddress = // got a port length
partial->u.Port.Length;
controller->OriginalBaseAddress = // got a port address
partial->u.Port.Start;
controller->ResourcePortType = // got a Port type
!!partial->Flags; // Mapped I/O or I/O Port
break;
}
case CmResourceTypeInterrupt: {
foundInterrupt = TRUE;
if (partial->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
controller->InterruptMode = Latched; // Edge Trigger
} else {
controller->InterruptMode = LevelSensitive; // Level
}
controller->OriginalIrql = partial->u.Interrupt.Level; // Irql
controller->OriginalVector = partial->u.Interrupt.Vector; // vector
break;
}
case CmResourceTypeDma: {
foundDma = TRUE;
controller->OriginalDmaChannel = partial->u.Dma.Channel;
break;
}
default: {
break;
}
}
}
//
// If we didn't get all the information then we return
// insufficient resources.
//
if ((!foundPort) ||
(!foundInterrupt) ||
(!foundDma)) {
return STATUS_INSUFFICIENT_RESOURCES;
}
return STATUS_SUCCESS;
}
NTSTATUS
SoundGetRegistryInformation(
OUT PCONFIG_CONTROLLER_DATA *ConfigData
)
/*++
Routine Description:
This routine is called by DriverEntry() to get information about the
devices to be supported from configuration mangement and/or the
hardware architecture layer (HAL).
Arguments:
ConfigData - a pointer to the pointer to a data structure that
describes the controllers and the drives attached to them
Return Value:
Returns STATUS_SUCCESS unless there is no drive 0 or we didn't get
any configuration information.
--*/
{
INTERFACE_TYPE InterfaceType;
NTSTATUS Status;
ULONG i;
CONFIGURATION_TYPE Dc;
CONFIGURATION_TYPE Fp;
*ConfigData = ExAllocatePool(
PagedPool,
sizeof(CONFIG_CONTROLLER_DATA)
);
if (!*ConfigData) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Zero out the config structure and fill in the actual
// controller numbers with -1's so that the callback routine
// can recognize a new controller.
//
RtlZeroMemory(
*ConfigData,
sizeof(CONFIG_CONTROLLER_DATA)
);
// Check ONLY Internal bus types.
// This Driver controlls audio controller that is on Internal
// bus.
InterfaceType = Internal;
Dc = AudioController;
Status = IoQueryDeviceDescription(
&InterfaceType,
NULL,
&Dc,
NULL,
NULL,
NULL,
SoundConfigCallBack,
*ConfigData
);
if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) {
ExFreePool(*ConfigData);
*ConfigData = NULL;
return Status;
}
return STATUS_SUCCESS;
}