mirror of https://github.com/lianthony/NT4.0
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
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;
|
|
}
|
|
|