547 lines
13 KiB
C
547 lines
13 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
devcaps.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains code for the device capabilities functions.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Nigel Thompson (nigelt) 7-Apr-1991
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Robin Speed (RobinSp) 29-Jan-1992
|
|||
|
- Add other devices and rewrite
|
|||
|
|
|||
|
Sameer Dekate (sameer@mips.com) 19-Aug-1992
|
|||
|
- Changes to support the MIPS sound board
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "sound.h"
|
|||
|
|
|||
|
// non-localized strings version is wrong !!!
|
|||
|
|
|||
|
WCHAR STR_SOUNDWAVEIN[] = L"MIPS Sound Version: 1.0";
|
|||
|
WCHAR STR_SOUNDWAVEOUT[]= L"MIPS Sound Version: 1.0";
|
|||
|
WCHAR STR_SOUNDAUX[] = L"MIPS Sound Version: 1.0";
|
|||
|
|
|||
|
//
|
|||
|
// local functions
|
|||
|
//
|
|||
|
|
|||
|
VOID sndSetUnicodeName(
|
|||
|
OUT PWSTR pUnicodeString,
|
|||
|
IN USHORT Size,
|
|||
|
OUT PUSHORT pUnicodeLength,
|
|||
|
IN PSZ pAnsiString
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
sndWaveOutGetCaps(
|
|||
|
IN PLOCAL_DEVICE_INFO pLDI,
|
|||
|
IN OUT PIRP pIrp,
|
|||
|
IN PIO_STACK_LOCATION IrpStack
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Return device capabilities for wave output device.
|
|||
|
Data is truncated if not enough space is provided.
|
|||
|
Irp is always completed.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pLDI - pointer to local device info
|
|||
|
pIrp - the Irp
|
|||
|
IrpStack - the current stack location
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - always succeeds
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
WAVEOUTCAPSW wc;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
|
|||
|
//
|
|||
|
// say how much we're sending back
|
|||
|
//
|
|||
|
|
|||
|
pIrp->IoStatus.Information =
|
|||
|
min(sizeof(wc),
|
|||
|
IrpStack->Parameters.DeviceIoControl.OutputBufferLength);
|
|||
|
|
|||
|
//
|
|||
|
// fill in the info
|
|||
|
//
|
|||
|
|
|||
|
wc.wMid = MM_MICROSOFT;
|
|||
|
wc.wPid = MM_SNDBLST_WAVEOUT;
|
|||
|
wc.vDriverVersion = DRIVER_VERSION;
|
|||
|
wc.dwFormats = WAVE_FORMAT_1M08 | // 11kHz mono 8 bit
|
|||
|
WAVE_FORMAT_1S08 | // 11kHz stereo 8 bit
|
|||
|
WAVE_FORMAT_1M16 | // 11kHz mono 16 bit
|
|||
|
WAVE_FORMAT_1S16 | // 11kHz stereo 16 bit
|
|||
|
WAVE_FORMAT_2M08 | // 22kHz mono 8 bit
|
|||
|
WAVE_FORMAT_2S08 | // 22kHz stereo 8 bit
|
|||
|
WAVE_FORMAT_2M16 | // 22kHz mono 16 bit
|
|||
|
WAVE_FORMAT_2S16 | // 22kHz stereo 16 bit
|
|||
|
WAVE_FORMAT_4M08 | // 44kHz mono 8 bit
|
|||
|
WAVE_FORMAT_4S08 | // 44kHz stereo 8 bit
|
|||
|
WAVE_FORMAT_4M16 | // 44kHz mono 16 bit
|
|||
|
WAVE_FORMAT_4S16; // 44kHz stereo 16 bit
|
|||
|
|
|||
|
|
|||
|
wc.wChannels = 2;
|
|||
|
wc.dwSupport = WAVECAPS_VOLUME|WAVECAPS_LRVOLUME;
|
|||
|
|
|||
|
//
|
|||
|
// Copy across unicode name
|
|||
|
//
|
|||
|
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
for ( i = 0; ; i++ ) {
|
|||
|
|
|||
|
wc.szPname[ i ] = STR_SOUNDWAVEOUT[ i ];
|
|||
|
if ( wc.szPname[ i ] == 0 ) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RtlMoveMemory(pIrp->AssociatedIrp.SystemBuffer,
|
|||
|
&wc,
|
|||
|
pIrp->IoStatus.Information);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
sndAuxGetCaps(
|
|||
|
IN PLOCAL_DEVICE_INFO pLDI,
|
|||
|
IN OUT PIRP pIrp,
|
|||
|
IN PIO_STACK_LOCATION IrpStack
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Return device capabilities for LINEIN AUX device.
|
|||
|
Data is truncated if not enough space is provided.
|
|||
|
Irp is always completed.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pLDI - pointer to local device info
|
|||
|
pIrp - the Irp
|
|||
|
IrpStack - the current stack location
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - always succeeds
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
AUXCAPSW ac;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
|
|||
|
//
|
|||
|
// say how much we're sending back
|
|||
|
//
|
|||
|
|
|||
|
pIrp->IoStatus.Information =
|
|||
|
min(sizeof(ac),
|
|||
|
IrpStack->Parameters.DeviceIoControl.OutputBufferLength);
|
|||
|
|
|||
|
//
|
|||
|
// fill in the info
|
|||
|
//
|
|||
|
|
|||
|
ac.wMid = MM_MICROSOFT;
|
|||
|
ac.wPid = MM_SNDBLST_WAVEIN;
|
|||
|
ac.vDriverVersion = DRIVER_VERSION;
|
|||
|
|
|||
|
if (pLDI->DeviceType == AUX_LINEIN)
|
|||
|
ac.wTechnology = AUXCAPS_AUXIN;
|
|||
|
|
|||
|
ac.dwSupport = AUXCAPS_VOLUME | AUXCAPS_LRVOLUME;
|
|||
|
|
|||
|
//
|
|||
|
// Copy across unicode name
|
|||
|
//
|
|||
|
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
for ( i = 0; ; i++ ) {
|
|||
|
|
|||
|
ac.szPname[ i ] = STR_SOUNDAUX[ i ];
|
|||
|
if ( ac.szPname[ i ] == 0 ) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RtlMoveMemory(pIrp->AssociatedIrp.SystemBuffer,
|
|||
|
&ac,
|
|||
|
pIrp->IoStatus.Information);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
sndWaveInGetCaps(
|
|||
|
IN PLOCAL_DEVICE_INFO pLDI,
|
|||
|
IN OUT PIRP pIrp,
|
|||
|
IN PIO_STACK_LOCATION IrpStack
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Return device capabilities for wave input device.
|
|||
|
Data is truncated if not enough space is provided.
|
|||
|
Irp is always completed.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pLDI - pointer to local device info
|
|||
|
pIrp - the Irp
|
|||
|
IrpStack - the current stack location
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - always succeeds
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
WAVEINCAPSW wc;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
|
|||
|
//
|
|||
|
// say how much we're sending back
|
|||
|
//
|
|||
|
|
|||
|
pIrp->IoStatus.Information =
|
|||
|
min(sizeof(wc),
|
|||
|
IrpStack->Parameters.DeviceIoControl.OutputBufferLength);
|
|||
|
|
|||
|
//
|
|||
|
// fill in the info
|
|||
|
//
|
|||
|
|
|||
|
wc.wMid = MM_MICROSOFT;
|
|||
|
wc.wPid = MM_SNDBLST_WAVEIN;
|
|||
|
wc.vDriverVersion = DRIVER_VERSION;
|
|||
|
wc.dwFormats = WAVE_FORMAT_1M08 | // 11kHz mono 8 bit
|
|||
|
WAVE_FORMAT_1S08 | // 11kHz stereo 8 bit
|
|||
|
WAVE_FORMAT_1M16 | // 11kHz mono 16 bit
|
|||
|
WAVE_FORMAT_1S16 | // 11kHz stereo 16 bit
|
|||
|
WAVE_FORMAT_2M08 | // 22kHz mono 8 bit
|
|||
|
WAVE_FORMAT_2S08 | // 22kHz stereo 8 bit
|
|||
|
WAVE_FORMAT_2M16 | // 22kHz mono 16 bit
|
|||
|
WAVE_FORMAT_2S16 | // 22kHz stereo 16 bit
|
|||
|
WAVE_FORMAT_4M08 | // 44kHz mono 8 bit
|
|||
|
WAVE_FORMAT_4S08 | // 44kHz stereo 8 bit
|
|||
|
WAVE_FORMAT_4M16 | // 44kHz mono 16 bit
|
|||
|
WAVE_FORMAT_4S16; // 44kHz stereo 16 bit
|
|||
|
|
|||
|
|
|||
|
wc.wChannels = 2;
|
|||
|
|
|||
|
//
|
|||
|
// Copy across unicode name
|
|||
|
//
|
|||
|
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
for ( i = 0; ; i++ ) {
|
|||
|
|
|||
|
wc.szPname[ i ] = STR_SOUNDWAVEIN[ i ];
|
|||
|
if ( wc.szPname[ i ] == 0 ) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RtlMoveMemory(pIrp->AssociatedIrp.SystemBuffer,
|
|||
|
&wc,
|
|||
|
pIrp->IoStatus.Information);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS sndIoctlQueryFormat(
|
|||
|
IN PLOCAL_DEVICE_INFO pLDI,
|
|||
|
IN OUT PIRP pIrp,
|
|||
|
IN PIO_STACK_LOCATION IrpStack
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Tell the caller whether the wave format specified (input or
|
|||
|
output) is supported
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pLDI - pointer to local device info
|
|||
|
pIrp - the Irp
|
|||
|
IrpStack - the current stack location
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - format is supported
|
|||
|
STATUS_NOT_SUPPORTED - format not supported
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PPCMWAVEFORMAT pFormat;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
PGLOBAL_DEVICE_INFO pGDI;
|
|||
|
PSOUND_REGISTERS pSoundRegisters;
|
|||
|
|
|||
|
ULONG ChangedShadowRegisters=0;
|
|||
|
|
|||
|
UCHAR regval, dfmtval, tempdfmtval;
|
|||
|
|
|||
|
pGDI = pLDI->pGlobalInfo;
|
|||
|
pSoundRegisters = pGDI->SoundHardware.SoundVirtualBase;
|
|||
|
|
|||
|
//
|
|||
|
// check the buffer really is big enough to contain the struct
|
|||
|
// we expect before digging into it. If not then assume it's a
|
|||
|
// format we don't know how to do.
|
|||
|
//
|
|||
|
|
|||
|
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength !=
|
|||
|
sizeof(PCMWAVEFORMAT)) {
|
|||
|
|
|||
|
dprintf1("Format data wrong size");
|
|||
|
return STATUS_NOT_SUPPORTED;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// we don't send anything back, just return a status value
|
|||
|
//
|
|||
|
|
|||
|
pIrp->IoStatus.Information = 0;
|
|||
|
|
|||
|
pFormat = (PPCMWAVEFORMAT)pIrp->AssociatedIrp.SystemBuffer;
|
|||
|
|
|||
|
//
|
|||
|
// Call our routine to see if the format is supported
|
|||
|
//
|
|||
|
|
|||
|
Status = sndQueryFormat(pLDI, pFormat);
|
|||
|
|
|||
|
//
|
|||
|
// If we're setting the format then copy it to our global info
|
|||
|
// In case it changed shift out the info to the Sound Board
|
|||
|
//
|
|||
|
|
|||
|
if (Status == STATUS_SUCCESS &&
|
|||
|
IrpStack->Parameters.DeviceIoControl.IoControlCode ==
|
|||
|
IOCTL_WAVE_SET_FORMAT) {
|
|||
|
|
|||
|
pGDI->SamplesPerSec = pFormat->wf.nSamplesPerSec;
|
|||
|
pGDI->BytesPerSample = pFormat->wBitsPerSample / 8;
|
|||
|
pGDI->Channels = pFormat->wf.nChannels;
|
|||
|
|
|||
|
regval = READAUDIO_CONFIG(&pSoundRegisters);
|
|||
|
regval &= ~(REC_XLATION | PLAY_XLATION);
|
|||
|
|
|||
|
if (pGDI->Channels == 1) {
|
|||
|
if (pGDI->BytesPerSample == 1) {
|
|||
|
regval |= (MONO_8BIT << REC_XLATION_SHIFT);
|
|||
|
regval |= (MONO_8BIT << PLAY_XLATION_SHIFT);
|
|||
|
} else {
|
|||
|
regval |= (MONO_16BIT << REC_XLATION_SHIFT);
|
|||
|
regval |= (MONO_16BIT << PLAY_XLATION_SHIFT);
|
|||
|
}
|
|||
|
} else {
|
|||
|
if (pGDI->BytesPerSample == 1) {
|
|||
|
regval |= (STEREO_8BIT << REC_XLATION_SHIFT);
|
|||
|
regval |= (STEREO_8BIT << PLAY_XLATION_SHIFT);
|
|||
|
} else {
|
|||
|
regval |= (STEREO_16BIT << REC_XLATION_SHIFT);
|
|||
|
regval |= (STEREO_16BIT << PLAY_XLATION_SHIFT);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (pGDI->BytesPerSample == 1) {
|
|||
|
regval |= (REC_8WAVE_ENABLE|PLAY_8WAVE_ENABLE);
|
|||
|
} else {
|
|||
|
regval &= ~(REC_8WAVE_ENABLE|PLAY_8WAVE_ENABLE);
|
|||
|
}
|
|||
|
|
|||
|
WRITEAUDIO_CONFIG(&pSoundRegisters, regval);
|
|||
|
dprintf3( "Bps/chn changed");
|
|||
|
|
|||
|
regval = READAUDIO_SCNTRL(&pSoundRegisters);
|
|||
|
dfmtval= READAUDIO_DATAFMT(&pSoundRegisters);
|
|||
|
tempdfmtval= dfmtval & DATA_CONVERSION_FREQ;
|
|||
|
|
|||
|
if (pGDI->SamplesPerSec == 11025) {
|
|||
|
if ((regval & CLKSRC_11KHZ) != CLKSRC_11KHZ){
|
|||
|
ChangedShadowRegisters = 1;
|
|||
|
regval &= ~CLOCK_SOURCE_SELECT;
|
|||
|
regval |= CLKSRC_11KHZ;
|
|||
|
}
|
|||
|
if (tempdfmtval != CONFREQ_11KHZ){
|
|||
|
ChangedShadowRegisters = 1;
|
|||
|
dfmtval &= ~DATA_CONVERSION_FREQ;
|
|||
|
dfmtval |= CONFREQ_11KHZ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (pGDI->SamplesPerSec == 22050) {
|
|||
|
if ((regval & CLKSRC_22KHZ) != CLKSRC_22KHZ){
|
|||
|
ChangedShadowRegisters = 1;
|
|||
|
regval &= ~CLOCK_SOURCE_SELECT;
|
|||
|
regval |= CLKSRC_22KHZ;
|
|||
|
}
|
|||
|
if (tempdfmtval != CONFREQ_22KHZ){
|
|||
|
ChangedShadowRegisters = 1;
|
|||
|
dfmtval &= ~DATA_CONVERSION_FREQ;
|
|||
|
dfmtval |= CONFREQ_22KHZ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (pGDI->SamplesPerSec == 44100) {
|
|||
|
if ((regval & CLKSRC_44KHZ) != CLKSRC_44KHZ){
|
|||
|
ChangedShadowRegisters = 1;
|
|||
|
regval &= ~CLOCK_SOURCE_SELECT;
|
|||
|
regval |= CLKSRC_44KHZ;
|
|||
|
}
|
|||
|
if (tempdfmtval != CONFREQ_44KHZ){
|
|||
|
ChangedShadowRegisters = 1;
|
|||
|
dfmtval &= ~DATA_CONVERSION_FREQ;
|
|||
|
dfmtval |= CONFREQ_44KHZ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ChangedShadowRegisters){
|
|||
|
|
|||
|
|
|||
|
// Whenever the CODEC is taken from data mode (normal mode
|
|||
|
// to control mode there is a slight click on the outside.
|
|||
|
// Here we try to avoid the clicks by using sndMute()
|
|||
|
// and sndSetOutputVolume()
|
|||
|
|
|||
|
sndMute( pGDI );
|
|||
|
|
|||
|
WRITEAUDIO_SCNTRL(&pSoundRegisters, regval);
|
|||
|
WRITEAUDIO_DATAFMT(&pSoundRegisters, dfmtval);
|
|||
|
|
|||
|
sndSetControlRegisters(pGDI);
|
|||
|
|
|||
|
sndSetOutputVolume( pGDI );
|
|||
|
|
|||
|
dprintf3( "shw set");
|
|||
|
}
|
|||
|
|
|||
|
dprintf3("Format Set");
|
|||
|
dprintf3("Format selected = freq=%d byt=%d nchl=%d",
|
|||
|
pLDI->pGlobalInfo->SamplesPerSec,
|
|||
|
pLDI->pGlobalInfo->BytesPerSample,
|
|||
|
pLDI->pGlobalInfo->Channels);
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS sndQueryFormat(
|
|||
|
IN PLOCAL_DEVICE_INFO pLDI,
|
|||
|
IN PPCMWAVEFORMAT pFormat
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Tell the caller whether the wave format specified (input or
|
|||
|
output) is supported
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pLDI - pointer to local device info
|
|||
|
pFormat - format being queried
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - format is supported
|
|||
|
STATUS_NOT_SUPPORTED - format not supported
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PGLOBAL_DEVICE_INFO pGDI;
|
|||
|
|
|||
|
pGDI = pLDI->pGlobalInfo;
|
|||
|
|
|||
|
if (pFormat->wf.wFormatTag != WAVE_FORMAT_PCM ||
|
|||
|
|
|||
|
pFormat->wf.nChannels > 2 ||
|
|||
|
pFormat->wf.nChannels < 1 ||
|
|||
|
|
|||
|
pLDI->DeviceType == WAVE_OUT &&
|
|||
|
(pFormat->wf.nSamplesPerSec != 11025 &&
|
|||
|
pFormat->wf.nSamplesPerSec != 22050 &&
|
|||
|
pFormat->wf.nSamplesPerSec != 44100 ||
|
|||
|
pFormat->wf.nBlockAlign < 1
|
|||
|
) ||
|
|||
|
|
|||
|
pLDI->DeviceType == WAVE_IN &&
|
|||
|
(pFormat->wf.nSamplesPerSec != 11025 &&
|
|||
|
pFormat->wf.nSamplesPerSec != 22050 &&
|
|||
|
pFormat->wf.nSamplesPerSec != 44100 ||
|
|||
|
pFormat->wf.nBlockAlign < 1
|
|||
|
) ||
|
|||
|
|
|||
|
pFormat->wf.nAvgBytesPerSec != (pFormat->wf.nSamplesPerSec *
|
|||
|
(pFormat->wBitsPerSample / 8) * pFormat->wf.nChannels) ||
|
|||
|
|
|||
|
(pFormat->wBitsPerSample != 8 &&
|
|||
|
pFormat->wBitsPerSample != 16)
|
|||
|
) {
|
|||
|
|
|||
|
dprintf5("sndQueryFormat: NOT SUPPORTED");
|
|||
|
return STATUS_NOT_SUPPORTED;
|
|||
|
} else {
|
|||
|
dprintf5("sndQueryFormat: SUPPORTED");
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|