//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 1999 // // File: sysaudio.c // //-------------------------------------------------------------------------- #include "redbook.h" #include "proto.h" #include #include #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; }