1124 lines
34 KiB
C
1124 lines
34 KiB
C
//+-------------------------------------------------------------------------
|
||
//
|
||
// Microsoft Windows
|
||
//
|
||
// Copyright (C) Microsoft Corporation, 1998 - 1999
|
||
//
|
||
// File: sysaudio.c
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
|
||
#include "redbook.h"
|
||
#include "proto.h"
|
||
#include <wdmguid.h>
|
||
#include <ksmedia.h>
|
||
|
||
#include "sysaudio.tmh"
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, AttachVirtualSource)
|
||
#pragma alloc_text(PAGE, CloseSysAudio)
|
||
#pragma alloc_text(PAGE, GetPinProperty)
|
||
#pragma alloc_text(PAGE, GetVolumeNodeId)
|
||
#pragma alloc_text(PAGE, InitializeVirtualSource)
|
||
#pragma alloc_text(PAGE, OpenInterfaceByGuid)
|
||
#pragma alloc_text(PAGE, OpenSysAudio)
|
||
#pragma alloc_text(PAGE, RedBookKsSetVolume)
|
||
#pragma alloc_text(PAGE, SetNextDeviceState)
|
||
#pragma alloc_text(PAGE, SysAudioPnpNotification)
|
||
#pragma alloc_text(PAGE, UninitializeVirtualSource)
|
||
#endif // ALLOC_PRAGMA
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
NTSTATUS
|
||
OpenSysAudio(
|
||
PREDBOOK_DEVICE_EXTENSION DeviceExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is a wrapper around all the work that must be done
|
||
just to open sysaudio for playback. the code was swiped from
|
||
Win98, and then translated into CSN (Cutler Standard Notation)
|
||
|
||
Arguments:
|
||
|
||
DeviceExtensionPinConnect - if successful, this will be the pin to send data to
|
||
|
||
PinFileObject - if successful, the file object this pin is associated
|
||
with is returned in this structure
|
||
|
||
PinDeviceObject - if successful, the device object this pin is
|
||
associated with is returned in this structure
|
||
|
||
VolumeNodeId - ?? No idea what this is... yet.
|
||
|
||
Return Value:
|
||
|
||
status
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
PFILE_OBJECT guidFileObject;
|
||
PFILE_OBJECT pinFileObject;
|
||
HANDLE deviceHandle;
|
||
NTSTATUS status;
|
||
HANDLE pinHandle;
|
||
ULONG volumeNodeId;
|
||
ULONG mixerPinId;
|
||
|
||
ULONG pins, pinId;
|
||
|
||
PAGED_CODE();
|
||
VerifyCalledByThread(DeviceExtension);
|
||
|
||
guidFileObject = NULL;
|
||
pinFileObject = NULL;
|
||
deviceHandle = NULL;
|
||
status = STATUS_SUCCESS;
|
||
pinHandle = NULL;
|
||
volumeNodeId = -1;
|
||
mixerPinId = DeviceExtension->Stream.MixerPinId;
|
||
|
||
|
||
TRY {
|
||
ASSERT( mixerPinId != MAXULONG );
|
||
|
||
//
|
||
// Note dependency on IoRegisterPlugPlayNotification() in pnp.c
|
||
//
|
||
|
||
status = OpenInterfaceByGuid(
|
||
//&KSCATEGORY_SYSAUDIO,
|
||
&KSCATEGORY_PREFERRED_WAVEOUT_DEVICE,
|
||
&deviceHandle,
|
||
&guidFileObject);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
LEAVE;
|
||
}
|
||
|
||
//
|
||
// Get the number of pins
|
||
//
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"SysAudio => Getting Pin Property PIN_CTYPES\n"));
|
||
|
||
status = GetPinProperty(guidFileObject,
|
||
KSPROPERTY_PIN_CTYPES,
|
||
0, // doesn't matter for ctypes
|
||
sizeof(pins),
|
||
&pins);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"SysAudio !! Unable to get number of pins %lx\n",
|
||
status));
|
||
RedBookLogError(DeviceExtension,
|
||
REDBOOK_ERR_CANNOT_GET_NUMBER_OF_PINS,
|
||
status);
|
||
LEAVE;
|
||
}
|
||
|
||
//
|
||
// Try to get a matching pin -- brute force method
|
||
//
|
||
|
||
for( pinId = 0; pinId < pins; pinId++) {
|
||
|
||
KSPIN_COMMUNICATION communication;
|
||
KSPIN_DATAFLOW dataFlow;
|
||
|
||
//
|
||
// check communication of the pin. accept either
|
||
// a sink or a pin that is both a source and sink
|
||
//
|
||
|
||
status = GetPinProperty(guidFileObject,
|
||
KSPROPERTY_PIN_COMMUNICATION,
|
||
pinId,
|
||
sizeof(communication),
|
||
&communication);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"SysAudio !! Pin %d communication query "
|
||
"failed %lx\n", pinId, status ));
|
||
continue;
|
||
}
|
||
|
||
if ( communication != KSPIN_COMMUNICATION_SINK &&
|
||
communication != KSPIN_COMMUNICATION_BOTH ) continue;
|
||
|
||
//
|
||
// only use this pin if it accepts incoming data
|
||
//
|
||
|
||
status = GetPinProperty(guidFileObject,
|
||
KSPROPERTY_PIN_DATAFLOW,
|
||
pinId,
|
||
sizeof(dataFlow),
|
||
&dataFlow);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"SysAudio !! Pin %d dataflow query failed %lx\n",
|
||
pinId, status));
|
||
continue;
|
||
}
|
||
|
||
if (dataFlow != KSPIN_DATAFLOW_IN) continue;
|
||
|
||
//
|
||
// we have found a matching pin, so attempt to connect
|
||
//
|
||
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"SysAudio => Attempt to connect to pin %d\n", pinId));
|
||
|
||
DeviceExtension->Stream.Connect.PinId = pinId;
|
||
DeviceExtension->Stream.Connect.PinToHandle = NULL;
|
||
|
||
status = KsCreatePin(deviceHandle,
|
||
&DeviceExtension->Stream.Connect,
|
||
GENERIC_WRITE, // FILE_WRITE_ACCESS
|
||
&pinHandle);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"SysAudio => Cannot create a writable pin %d\n",
|
||
pinId));
|
||
continue;
|
||
}
|
||
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"SysAudio => Connected to pin %d\n", pinId ));
|
||
|
||
//
|
||
// get the object associated with the pinHandle just created
|
||
// so we can then get other information about the pin
|
||
//
|
||
|
||
status = ObReferenceObjectByHandle(pinHandle,
|
||
GENERIC_READ | GENERIC_WRITE,
|
||
NULL,
|
||
KernelMode,
|
||
&pinFileObject,
|
||
NULL);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"SysAudio !! Object from handle for pin "
|
||
"failed %lx\n", status));
|
||
LEAVE;
|
||
}
|
||
|
||
//
|
||
// this allows us to change our output volume
|
||
// this just sends a ks ioctl, no referencing done here
|
||
//
|
||
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"SysAudio => Getting VolumeNodeId\n"));
|
||
|
||
status = GetVolumeNodeId(pinFileObject,
|
||
&volumeNodeId);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"SysAudio !! Unable to get volume node "
|
||
"id %lx\n", status));
|
||
LEAVE;
|
||
}
|
||
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"SysAudio => Attaching PinFileObject %p "
|
||
"to MixerPinId %d\n", pinFileObject,
|
||
mixerPinId));
|
||
|
||
//
|
||
// this just sends a ks ioctl, no referencing done here
|
||
//
|
||
|
||
status = AttachVirtualSource(pinFileObject, mixerPinId);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"SysAudio !! Unable to attach virtual "
|
||
"source %lx\n", status));
|
||
LEAVE;
|
||
}
|
||
|
||
//
|
||
// successful completion
|
||
//
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
LEAVE;
|
||
}
|
||
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"Sysaudio !! Unable to connect to any pins\n"));
|
||
RedBookLogError(DeviceExtension,
|
||
REDBOOK_ERR_CANNOT_CONNECT_TO_PLAYBACK_PINS,
|
||
status);
|
||
|
||
//
|
||
// no pin succeeded, so set status to failure
|
||
//
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
LEAVE;
|
||
|
||
|
||
} FINALLY {
|
||
|
||
//
|
||
// the pin handle is not required, as we've referenced
|
||
// the pin in pinFileObject. close it here.
|
||
//
|
||
|
||
if (pinHandle != NULL) {
|
||
ZwClose(pinHandle);
|
||
pinHandle = NULL;
|
||
}
|
||
|
||
//
|
||
// the device handle is only required to create
|
||
// the actual pin. close it here.
|
||
//
|
||
|
||
if (deviceHandle != NULL) {
|
||
ZwClose(deviceHandle);
|
||
deviceHandle = NULL;
|
||
}
|
||
|
||
//
|
||
// the guidFileObject is also only required to query
|
||
// and create the pins. close it here.
|
||
//
|
||
// (pinFileObject is still important)
|
||
//
|
||
|
||
if (guidFileObject != NULL) {
|
||
ObDereferenceObject(guidFileObject);
|
||
guidFileObject = NULL;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
if (pinFileObject != NULL) {
|
||
ObDereferenceObject(pinFileObject);
|
||
pinFileObject = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// the MixerPinId should not have changed in this function
|
||
//
|
||
|
||
ASSERT(mixerPinId == DeviceExtension->Stream.MixerPinId);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
DeviceExtension->Stream.PinFileObject = pinFileObject;
|
||
DeviceExtension->Stream.PinDeviceObject =
|
||
IoGetRelatedDeviceObject(pinFileObject);
|
||
DeviceExtension->Stream.VolumeNodeId = volumeNodeId;
|
||
|
||
} else {
|
||
|
||
DeviceExtension->Stream.PinFileObject = NULL;
|
||
DeviceExtension->Stream.PinDeviceObject = NULL;
|
||
DeviceExtension->Stream.VolumeNodeId = -1;
|
||
|
||
}
|
||
|
||
return status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
CloseSysAudio(
|
||
PREDBOOK_DEVICE_EXTENSION DeviceExtension
|
||
)
|
||
{
|
||
PAGED_CODE();
|
||
VerifyCalledByThread(DeviceExtension);
|
||
|
||
ASSERT(DeviceExtension->Stream.PinFileObject);
|
||
ASSERT(DeviceExtension->Stream.PinDeviceObject);
|
||
|
||
ObDereferenceObject(DeviceExtension->Stream.PinFileObject);
|
||
DeviceExtension->Stream.PinDeviceObject = NULL;
|
||
DeviceExtension->Stream.PinFileObject = NULL;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
GetPinProperty(
|
||
IN PFILE_OBJECT FileObject,
|
||
IN ULONG PropertyId,
|
||
IN ULONG PinId,
|
||
IN ULONG PropertySize,
|
||
OUT PVOID Property
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
another wrapper to hide getting pin properties
|
||
|
||
Arguments:
|
||
|
||
FileObject - file object to query
|
||
|
||
PropertyId - what property to query
|
||
|
||
PinId - which pin to query
|
||
|
||
PropertySize - size of output buffer
|
||
|
||
Property - output buffer for property
|
||
|
||
Return Value:
|
||
|
||
status
|
||
|
||
--*/
|
||
{
|
||
ULONG bytesReturned;
|
||
KSP_PIN prop;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
prop.Property.Set = KSPROPSETID_Pin;
|
||
prop.Property.Id = PropertyId;
|
||
prop.Property.Flags = KSPROPERTY_TYPE_GET;
|
||
prop.PinId = PinId;
|
||
prop.Reserved = 0;
|
||
|
||
status = KsSynchronousIoControlDevice( FileObject,
|
||
KernelMode,
|
||
IOCTL_KS_PROPERTY,
|
||
&prop,
|
||
sizeof(prop),
|
||
Property,
|
||
PropertySize,
|
||
&bytesReturned
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"GetPinProperty !! fileobj %p property %p "
|
||
"pin %d status %lx\n",
|
||
FileObject, Property, PinId, status));
|
||
return status;
|
||
}
|
||
|
||
ASSERT( bytesReturned == PropertySize );
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
GetVolumeNodeId(
|
||
IN PFILE_OBJECT FileObject,
|
||
OUT PULONG VolumeNodeId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the pin to set the volume for playback
|
||
|
||
Arguments:
|
||
|
||
FileObject - The fileobject which contains the pin
|
||
|
||
VolumeNodeId - id of the volume node
|
||
|
||
Return Value:
|
||
|
||
status
|
||
|
||
--*/
|
||
{
|
||
KSPROPERTY property;
|
||
ULONG bytesReturned;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
property.Set = KSPROPSETID_Sysaudio_Pin;
|
||
property.Id = KSPROPERTY_SYSAUDIO_PIN_VOLUME_NODE;
|
||
property.Flags = KSPROPERTY_TYPE_GET;
|
||
|
||
status = KsSynchronousIoControlDevice( FileObject,
|
||
KernelMode,
|
||
IOCTL_KS_PROPERTY,
|
||
&property,
|
||
sizeof(property),
|
||
VolumeNodeId,
|
||
sizeof(ULONG),
|
||
&bytesReturned
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"GetVolumeNodeId !! fileobj %p status %lx\n",
|
||
FileObject, status));
|
||
return status;
|
||
}
|
||
|
||
ASSERT(bytesReturned == sizeof(ULONG));
|
||
return(status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
UninitializeVirtualSource(
|
||
PREDBOOK_DEVICE_EXTENSION DeviceExtension
|
||
)
|
||
{
|
||
ULONG state;
|
||
|
||
PAGED_CODE();
|
||
VerifyCalledByThread(DeviceExtension);
|
||
|
||
ASSERT(DeviceExtension->Stream.MixerPinId != -1);
|
||
ASSERT(DeviceExtension->Stream.MixerFileObject != NULL);
|
||
|
||
state = GetCdromState(DeviceExtension);
|
||
ASSERT(state == CD_STOPPED);
|
||
|
||
DeviceExtension->Stream.MixerPinId = -1;
|
||
ObDereferenceObject(DeviceExtension->Stream.MixerFileObject);
|
||
DeviceExtension->Stream.MixerFileObject = NULL;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
InitializeVirtualSource(
|
||
PREDBOOK_DEVICE_EXTENSION DeviceExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
MixerPinId - initialized to the correct pin id of mixer
|
||
|
||
Return Value:
|
||
|
||
status
|
||
|
||
--*/
|
||
{
|
||
SYSAUDIO_CREATE_VIRTUAL_SOURCE createVirtualSource;
|
||
PFILE_OBJECT fileObject;
|
||
NTSTATUS status;
|
||
HANDLE deviceHandle;
|
||
ULONG bytesReturned;
|
||
ULONG mixerPinId;
|
||
ULONG state;
|
||
|
||
PAGED_CODE();
|
||
VerifyCalledByThread(DeviceExtension);
|
||
|
||
ASSERT(DeviceExtension->Stream.MixerPinId == -1);
|
||
ASSERT(DeviceExtension->Stream.MixerFileObject == NULL);
|
||
|
||
state = GetCdromState(DeviceExtension);
|
||
ASSERT(state == CD_STOPPED);
|
||
|
||
fileObject = NULL;
|
||
status = STATUS_SUCCESS;
|
||
deviceHandle = NULL;
|
||
mixerPinId = -1;
|
||
|
||
//
|
||
// use IoGetDeviceInterfaces()
|
||
//
|
||
status = OpenInterfaceByGuid(&KSCATEGORY_SYSAUDIO,
|
||
&deviceHandle,
|
||
&fileObject);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
RedBookLogError(DeviceExtension,
|
||
REDBOOK_ERR_CANNOT_OPEN_SYSAUDIO_MIXER,
|
||
status);
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"CreateVirtSource !! Unable to open sysaudio\\mixer %lx\n",
|
||
status));
|
||
goto exit;
|
||
}
|
||
|
||
createVirtualSource.Property.Set = KSPROPSETID_Sysaudio;
|
||
createVirtualSource.Property.Id = KSPROPERTY_SYSAUDIO_CREATE_VIRTUAL_SOURCE;
|
||
createVirtualSource.Property.Flags = KSPROPERTY_TYPE_GET;
|
||
createVirtualSource.PinCategory = KSNODETYPE_CD_PLAYER;
|
||
createVirtualSource.PinName = KSNODETYPE_CD_PLAYER;
|
||
|
||
status = KsSynchronousIoControlDevice(fileObject,
|
||
KernelMode,
|
||
IOCTL_KS_PROPERTY,
|
||
&createVirtualSource,
|
||
sizeof(createVirtualSource),
|
||
&mixerPinId,
|
||
sizeof(ULONG), // MixerPinId
|
||
&bytesReturned
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
RedBookLogError(DeviceExtension,
|
||
REDBOOK_ERR_CANNOT_CREATE_VIRTUAL_SOURCE,
|
||
status);
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
|
||
"CreateVirtSource !! creating virtual source "
|
||
"failed %lx\n", status));
|
||
goto exit;
|
||
}
|
||
|
||
ASSERT( bytesReturned == sizeof(ULONG) );
|
||
|
||
exit:
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
DeviceExtension->Stream.MixerPinId = mixerPinId;
|
||
DeviceExtension->Stream.MixerFileObject = fileObject;
|
||
|
||
} else if (fileObject != NULL) {
|
||
|
||
//
|
||
// failed to open, so deref object if non-null
|
||
//
|
||
|
||
ObDereferenceObject(fileObject);
|
||
fileObject = NULL;
|
||
|
||
}
|
||
|
||
if (deviceHandle != NULL) {
|
||
ZwClose(deviceHandle);
|
||
deviceHandle = NULL;
|
||
}
|
||
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
AttachVirtualSource(
|
||
IN PFILE_OBJECT PinFileObject,
|
||
IN ULONG MixerPinId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
FileObject - ??
|
||
|
||
MixerPinId - ??
|
||
|
||
Return Value:
|
||
|
||
status
|
||
|
||
--*/
|
||
{
|
||
SYSAUDIO_ATTACH_VIRTUAL_SOURCE attachVirtualSource;
|
||
NTSTATUS status;
|
||
ULONG bytesReturned;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// if the source hasn't been initialized, reject this
|
||
// request as invalid
|
||
//
|
||
|
||
if(MixerPinId == MAXULONG) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
|
||
"AttatchVirtSource !! Mixer Pin uninitialized\n"));
|
||
ASSERT(!"Mixer Pin Uninitialized");
|
||
return STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
attachVirtualSource.Property.Set = KSPROPSETID_Sysaudio_Pin;
|
||
attachVirtualSource.Property.Id = KSPROPERTY_SYSAUDIO_ATTACH_VIRTUAL_SOURCE;
|
||
attachVirtualSource.Property.Flags = KSPROPERTY_TYPE_SET;
|
||
attachVirtualSource.MixerPinId = MixerPinId;
|
||
|
||
status = KsSynchronousIoControlDevice(PinFileObject,
|
||
KernelMode,
|
||
IOCTL_KS_PROPERTY,
|
||
&attachVirtualSource,
|
||
sizeof(attachVirtualSource),
|
||
NULL,
|
||
0,
|
||
&bytesReturned
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"AttachVirtSource !! Couldn't attatch %lx\n", status));
|
||
return status;
|
||
}
|
||
return status;
|
||
}
|
||
|
||
VOID
|
||
SetNextDeviceState(
|
||
PREDBOOK_DEVICE_EXTENSION DeviceExtension,
|
||
KSSTATE State
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
KSIDENTIFIER stateProperty;
|
||
NTSTATUS status;
|
||
ULONG bytesReturned;
|
||
KSSTATE acquireState;
|
||
PFILE_OBJECT fileObject;
|
||
|
||
PAGED_CODE();
|
||
VerifyCalledByThread(DeviceExtension);
|
||
|
||
fileObject = DeviceExtension->Stream.PinFileObject;
|
||
|
||
acquireState = KSSTATE_ACQUIRE;
|
||
|
||
stateProperty.Set = KSPROPSETID_Connection;
|
||
stateProperty.Id = KSPROPERTY_CONNECTION_STATE;
|
||
stateProperty.Flags = KSPROPERTY_TYPE_SET;
|
||
|
||
ASSERT(fileObject);
|
||
status = KsSynchronousIoControlDevice(fileObject,
|
||
KernelMode,
|
||
IOCTL_KS_PROPERTY,
|
||
&stateProperty,
|
||
sizeof(stateProperty),
|
||
&acquireState,
|
||
sizeof(acquireState),
|
||
&bytesReturned
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
|
||
"SetDeviceState => (1) Audio device error %x. need to "
|
||
"stop playback AND change audio devices\n", status));
|
||
}
|
||
|
||
//
|
||
// now that it's acquired, set the new state
|
||
//
|
||
|
||
stateProperty.Set = KSPROPSETID_Connection;
|
||
stateProperty.Id = KSPROPERTY_CONNECTION_STATE;
|
||
stateProperty.Flags = KSPROPERTY_TYPE_SET;
|
||
|
||
status = KsSynchronousIoControlDevice(fileObject,
|
||
KernelMode,
|
||
IOCTL_KS_PROPERTY,
|
||
&stateProperty,
|
||
sizeof(stateProperty),
|
||
&State,
|
||
sizeof(State),
|
||
&bytesReturned
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
|
||
"SetDeviceState => (2) Audio device error %x. need to "
|
||
"stop playback AND change audio devices\n", status));
|
||
}
|
||
return;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// this table is in 1/65536 decibles for a UCHAR setting: //
|
||
// 20 * log10( Level / 256 ) * 65536 //
|
||
// //
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
AttenuationTable[] = {
|
||
0x7fffffff, 0xffcfd5d0, 0xffd5db16, 0xffd960ad, // 0- 3
|
||
0xffdbe05c, 0xffddd08a, 0xffdf65f3, 0xffe0bcb7, // 4- 7
|
||
0xffe1e5a2, 0xffe2eb89, 0xffe3d5d0, 0xffe4a9be, // 8- b
|
||
0xffe56b39, 0xffe61d34, 0xffe6c1fd, 0xffe75b67, // c- f
|
||
0xffe7eae8, 0xffe871b6, 0xffe8f0cf, 0xffe96908, // 10-13
|
||
0xffe9db16, 0xffea4793, 0xffeaaf04, 0xffeb11dc, // 14-17
|
||
0xffeb707f, 0xffebcb44, 0xffec227a, 0xffec7665, // 18-1b
|
||
0xffecc743, 0xffed154b, 0xffed60ad, 0xffeda996, // 1c-1f
|
||
0xffedf02e, 0xffee349b, 0xffee76fc, 0xffeeb771, // 20-23
|
||
0xffeef615, 0xffef3302, 0xffef6e4e, 0xffefa810, // 24-27
|
||
0xffefe05c, 0xfff01744, 0xfff04cda, 0xfff0812c, // 28-2b
|
||
0xfff0b44b, 0xfff0e643, 0xfff11722, 0xfff146f4, // 2c-2f
|
||
0xfff175c5, 0xfff1a39e, 0xfff1d08a, 0xfff1fc93, // 30-33
|
||
0xfff227c0, 0xfff2521b, 0xfff27bab, 0xfff2a478, // 34-37
|
||
0xfff2cc89, 0xfff2f3e5, 0xfff31a91, 0xfff34093, // 38-3b
|
||
0xfff365f3, 0xfff38ab4, 0xfff3aedc, 0xfff3d270, // 3c-3f
|
||
0xfff3f574, 0xfff417ee, 0xfff439e1, 0xfff45b51, // 40-43
|
||
0xfff47c42, 0xfff49cb8, 0xfff4bcb7, 0xfff4dc42, // 44-47
|
||
0xfff4fb5b, 0xfff51a07, 0xfff53848, 0xfff55621, // 48-4b
|
||
0xfff57394, 0xfff590a5, 0xfff5ad56, 0xfff5c9aa, // 4c-4f
|
||
0xfff5e5a2, 0xfff60142, 0xfff61c8a, 0xfff6377e, // 50-53
|
||
0xfff65220, 0xfff66c70, 0xfff68672, 0xfff6a027, // 54-57
|
||
0xfff6b991, 0xfff6d2b1, 0xfff6eb89, 0xfff7041b, // 58-5b
|
||
0xfff71c68, 0xfff73472, 0xfff74c3a, 0xfff763c2, // 5c-5f
|
||
0xfff77b0b, 0xfff79216, 0xfff7a8e4, 0xfff7bf77, // 60-63
|
||
0xfff7d5d0, 0xfff7ebf0, 0xfff801d9, 0xfff8178a, // 64-67
|
||
0xfff82d06, 0xfff8424d, 0xfff85761, 0xfff86c42, // 68-6b
|
||
0xfff880f1, 0xfff89570, 0xfff8a9be, 0xfff8bdde, // 6c-6f
|
||
0xfff8d1cf, 0xfff8e593, 0xfff8f92b, 0xfff90c96, // 70-73
|
||
0xfff91fd7, 0xfff932ed, 0xfff945d9, 0xfff9589d, // 74-77
|
||
0xfff96b39, 0xfff97dad, 0xfff98ffa, 0xfff9a221, // 78-7b
|
||
0xfff9b422, 0xfff9c5fe, 0xfff9d7b6, 0xfff9e94a, // 7c-7f
|
||
0xfff9faba, 0xfffa0c08, 0xfffa1d34, 0xfffa2e3e, // 80-83
|
||
0xfffa3f27, 0xfffa4fef, 0xfffa6097, 0xfffa711f, // 84-87
|
||
0xfffa8188, 0xfffa91d3, 0xfffaa1ff, 0xfffab20d, // 88-8b
|
||
0xfffac1fd, 0xfffad1d1, 0xfffae188, 0xfffaf122, // 8c-8f
|
||
0xfffb00a1, 0xfffb1004, 0xfffb1f4d, 0xfffb2e7a, // 90-93
|
||
0xfffb3d8e, 0xfffb4c87, 0xfffb5b67, 0xfffb6a2d, // 94-97
|
||
0xfffb78da, 0xfffb876f, 0xfffb95eb, 0xfffba450, // 98-9b
|
||
0xfffbb29c, 0xfffbc0d2, 0xfffbcef0, 0xfffbdcf7, // 9c-9f
|
||
0xfffbeae8, 0xfffbf8c3, 0xfffc0688, 0xfffc1437, // a0-a3
|
||
0xfffc21d0, 0xfffc2f55, 0xfffc3cc4, 0xfffc4a1f, // a4-a7
|
||
0xfffc5766, 0xfffc6498, 0xfffc71b6, 0xfffc7ec1, // a8-ab
|
||
0xfffc8bb8, 0xfffc989c, 0xfffca56d, 0xfffcb22b, // ac-af
|
||
0xfffcbed7, 0xfffccb70, 0xfffcd7f7, 0xfffce46c, // b0-b3
|
||
0xfffcf0cf, 0xfffcfd21, 0xfffd0961, 0xfffd1590, // b4-b7
|
||
0xfffd21ae, 0xfffd2dbc, 0xfffd39b8, 0xfffd45a4, // b8-bb
|
||
0xfffd5180, 0xfffd5d4c, 0xfffd6908, 0xfffd74b4, // bc-bf
|
||
0xfffd8051, 0xfffd8bde, 0xfffd975c, 0xfffda2ca, // c0-c3
|
||
0xfffdae2a, 0xfffdb97b, 0xfffdc4bd, 0xfffdcff1, // c4-c7
|
||
0xfffddb16, 0xfffde62d, 0xfffdf136, 0xfffdfc31, // c8-cb
|
||
0xfffe071f, 0xfffe11fe, 0xfffe1cd0, 0xfffe2795, // cc-cf
|
||
0xfffe324c, 0xfffe3cf6, 0xfffe4793, 0xfffe5224, // d0-d3
|
||
0xfffe5ca7, 0xfffe671e, 0xfffe7188, 0xfffe7be6, // d4-d7
|
||
0xfffe8637, 0xfffe907d, 0xfffe9ab6, 0xfffea4e3, // d8-db
|
||
0xfffeaf04, 0xfffeb91a, 0xfffec324, 0xfffecd22, // dc-df
|
||
0xfffed715, 0xfffee0fd, 0xfffeead9, 0xfffef4aa, // e0-e3
|
||
0xfffefe71, 0xffff082c, 0xffff11dc, 0xffff1b82, // e4-e7
|
||
0xffff251d, 0xffff2ead, 0xffff3833, 0xffff41ae, // e8-eb
|
||
0xffff4b1f, 0xffff5486, 0xffff5de3, 0xffff6736, // ec-ef
|
||
0xffff707f, 0xffff79be, 0xffff82f3, 0xffff8c1e, // f0-f3
|
||
0xffff9540, 0xffff9e58, 0xffffa767, 0xffffb06c, // f4-f7
|
||
0xffffb968, 0xffffc25b, 0xffffcb44, 0xffffd425, // f8-fb
|
||
0xffffdcfc, 0xffffe5ca, 0xffffee90, 0x00000000, // fc-ff
|
||
};
|
||
|
||
#define DA_CHANNEL_LEFT 0
|
||
#define DA_CHANNEL_RIGHT 1
|
||
#define DA_CHANNEL_MAX 2
|
||
|
||
VOID
|
||
RedBookKsSetVolume(
|
||
PREDBOOK_DEVICE_EXTENSION DeviceExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
|
||
KSNODEPROPERTY_AUDIO_CHANNEL volumeProperty;
|
||
VOLUME_CONTROL volume;
|
||
NTSTATUS status;
|
||
ULONG32 channel;
|
||
ULONG32 bytesReturned = 0;
|
||
BOOLEAN mute;
|
||
|
||
PAGED_CODE();
|
||
VerifyCalledByThread(DeviceExtension);
|
||
|
||
volume = DeviceExtension->CDRom.Volume;
|
||
|
||
//
|
||
// These settings are common for all the sets
|
||
//
|
||
|
||
volumeProperty.NodeProperty.Property.Set = KSPROPSETID_Audio;
|
||
volumeProperty.NodeProperty.Property.Flags = KSPROPERTY_TYPE_SET |
|
||
KSPROPERTY_TYPE_TOPOLOGY;
|
||
volumeProperty.NodeProperty.NodeId = DeviceExtension->Stream.VolumeNodeId;
|
||
|
||
//
|
||
// Do both Left and right channels
|
||
//
|
||
|
||
for ( channel = 0; channel < DA_CHANNEL_MAX; channel++ ) {
|
||
|
||
//
|
||
// handle the correct channel
|
||
//
|
||
|
||
volumeProperty.Channel = channel;
|
||
|
||
//
|
||
// if not muting the channel, set the volume
|
||
//
|
||
|
||
if ( volume.PortVolume[channel] != 0 ) {
|
||
ULONG32 level;
|
||
ULONG32 index;
|
||
|
||
volumeProperty.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
|
||
|
||
level = AttenuationTable[ volume.PortVolume[channel] ];
|
||
|
||
ASSERT(DeviceExtension->Stream.PinFileObject);
|
||
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"SetVolume => Setting channel %d to %lx\n",
|
||
channel, level ));
|
||
status = KsSynchronousIoControlDevice(DeviceExtension->Stream.PinFileObject,
|
||
KernelMode,
|
||
IOCTL_KS_PROPERTY,
|
||
&volumeProperty,
|
||
sizeof(volumeProperty),
|
||
&level,
|
||
sizeof(level),
|
||
&bytesReturned
|
||
);
|
||
// ASSERT( NT_SUCCESS(status) );
|
||
mute = FALSE;
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"SetVolume => Un-Muting channel %d\n", channel));
|
||
} else {
|
||
mute = TRUE;
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"SetVolume => Muting channel %d\n", channel));
|
||
}
|
||
volumeProperty.NodeProperty.Property.Id = KSPROPERTY_AUDIO_MUTE;
|
||
|
||
status = KsSynchronousIoControlDevice(DeviceExtension->Stream.PinFileObject,
|
||
KernelMode,
|
||
IOCTL_KS_PROPERTY,
|
||
&volumeProperty,
|
||
sizeof(volumeProperty),
|
||
&mute,
|
||
sizeof(mute),
|
||
&bytesReturned
|
||
);
|
||
// ASSERT( NT_SUCCESS(status) );
|
||
|
||
}
|
||
|
||
//
|
||
// End of all channels
|
||
//
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
OpenInterfaceByGuid(
|
||
IN CONST GUID * InterfaceClassGuid,
|
||
OUT HANDLE * Handle,
|
||
OUT PFILE_OBJECT * FileObject
|
||
)
|
||
{
|
||
PWSTR tempString;
|
||
PWSTR symbolicLinkList;
|
||
HANDLE localHandle;
|
||
PFILE_OBJECT localFileObject;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
localHandle = NULL;
|
||
tempString = NULL;
|
||
symbolicLinkList = NULL;
|
||
*Handle = NULL;
|
||
*FileObject = NULL;
|
||
|
||
status = IoGetDeviceInterfaces(InterfaceClassGuid,
|
||
// currently, the GUID is one of
|
||
// KSCATEGORY_PREFERRED_WAVEOUT_DEVICE
|
||
// or KSCATEGORY_SYSAUDIO
|
||
NULL, // no preferred device object
|
||
0,
|
||
&symbolicLinkList);
|
||
if (!NT_SUCCESS(status)) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"OpenDevice !! IoGetDeviceInterfaces failed %x\n",
|
||
status));
|
||
return status;
|
||
}
|
||
|
||
#if DBG
|
||
tempString = symbolicLinkList;
|
||
while (*tempString != UNICODE_NULL) {
|
||
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"OpenDevice => Possible Device: %ws\n", tempString));
|
||
|
||
//
|
||
// get the next symbolic link
|
||
//
|
||
|
||
while(*tempString++ != UNICODE_NULL) {
|
||
NOTHING;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// this code is proudly propogated from wdmaud.sys
|
||
//
|
||
|
||
tempString = symbolicLinkList;
|
||
while (*tempString != UNICODE_NULL) {
|
||
|
||
IO_STATUS_BLOCK ioStatusBlock;
|
||
UNICODE_STRING deviceString;
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
|
||
RtlInitUnicodeString( &deviceString, tempString);
|
||
|
||
InitializeObjectAttributes(&objectAttributes,
|
||
&deviceString,
|
||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// could use IoCreateFile(), based on
|
||
// ntos\dd\wdm\audio\legacy\wdmaud.sys\sysaudio.c:OpenDevice()
|
||
//
|
||
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"OpenDevice => Opening %ws\n", tempString));
|
||
status = ZwCreateFile(&localHandle,
|
||
GENERIC_READ | GENERIC_WRITE,
|
||
&objectAttributes,
|
||
&ioStatusBlock,
|
||
NULL, // ignored on non-create
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
0, // no share access
|
||
FILE_OPEN, // open the existing file
|
||
0, NULL, 0 // options
|
||
);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
ASSERT(localHandle != NULL);
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"OpenDevice => Opened %ws\n", tempString));
|
||
break; // out of the while loop
|
||
|
||
}
|
||
|
||
ASSERT(localHandle == NULL);
|
||
|
||
//
|
||
// get the next symbolic link
|
||
//
|
||
|
||
while(*tempString++ != UNICODE_NULL) {
|
||
NOTHING;
|
||
}
|
||
|
||
}
|
||
|
||
if (symbolicLinkList != NULL) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"OpenDevice => Freeing list from IoGetDevInt...\n"));
|
||
ExFreePool(symbolicLinkList);
|
||
symbolicLinkList = NULL;
|
||
tempString = NULL;
|
||
}
|
||
|
||
|
||
//
|
||
// if succeeded to open the file, try to get
|
||
// the FileObject that is related to this handle.
|
||
//
|
||
|
||
if (localHandle != NULL) {
|
||
|
||
status = ObReferenceObjectByHandle(localHandle,
|
||
GENERIC_READ | GENERIC_WRITE,
|
||
NULL,
|
||
KernelMode,
|
||
&localFileObject, // double pointer
|
||
NULL);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
||
"OpenDevice => Succeeded\n"));
|
||
|
||
*Handle = localHandle;
|
||
*FileObject = localFileObject;
|
||
|
||
return status; // Exit point for success
|
||
}
|
||
|
||
ZwClose(localHandle);
|
||
localHandle = NULL;
|
||
|
||
}
|
||
|
||
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
||
"OpenDevice => unable to open any audio devices\n"));
|
||
status = STATUS_NO_SUCH_DEVICE;
|
||
return status;
|
||
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SysAudioPnpNotification(
|
||
PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification,
|
||
PREDBOOK_DEVICE_EXTENSION DeviceExtension
|
||
)
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
|
||
PAGED_CODE();
|
||
|
||
InterlockedExchange(&DeviceExtension->Stream.UpdateMixerPin, 1);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|