mirror of
https://github.com/reactos/reactos.git
synced 2025-08-11 13:25:36 +00:00
Create a branch for header work.
svn path=/branches/header-work/; revision=45691
This commit is contained in:
parent
14fe274b1c
commit
9ea495ba33
19538 changed files with 0 additions and 1063950 deletions
515
drivers/wdm/audio/sysaudio/control.c
Normal file
515
drivers/wdm/audio/sysaudio/control.c
Normal file
|
@ -0,0 +1,515 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel Streaming
|
||||
* FILE: drivers/wdm/audio/sysaudio/control.c
|
||||
* PURPOSE: System Audio graph builder
|
||||
* PROGRAMMER: Johannes Anderwald
|
||||
*/
|
||||
|
||||
#include "sysaudio.h"
|
||||
|
||||
const GUID KSPROPSETID_Sysaudio = {0xCBE3FAA0L, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
|
||||
const GUID KSPROPSETID_Sysaudio_Pin = {0xA3A53220L, 0xC6E4, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
|
||||
const GUID KSPROPSETID_General = {0x1464EDA5L, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
|
||||
const GUID KSPROPSETID_Pin = {0x8C134960L, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
|
||||
const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
|
||||
const GUID KSPROPSETID_Topology = {0x720D4AC0L, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
|
||||
const GUID KSDATAFORMAT_TYPE_AUDIO = {0x73647561L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
|
||||
const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
|
||||
const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
|
||||
|
||||
NTSTATUS
|
||||
SetIrpIoStatus(
|
||||
IN PIRP Irp,
|
||||
IN NTSTATUS Status,
|
||||
IN ULONG Length)
|
||||
{
|
||||
Irp->IoStatus.Information = Length;
|
||||
Irp->IoStatus.Status = Status;
|
||||
if (Status != STATUS_PENDING)
|
||||
{
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
IoMarkIrpPending(Irp);
|
||||
}
|
||||
return Status;
|
||||
|
||||
}
|
||||
|
||||
PKSAUDIO_DEVICE_ENTRY
|
||||
GetListEntry(
|
||||
IN PLIST_ENTRY Head,
|
||||
IN ULONG Index)
|
||||
{
|
||||
PLIST_ENTRY Entry = Head->Flink;
|
||||
|
||||
while(Index-- && Entry != Head)
|
||||
Entry = Entry->Flink;
|
||||
|
||||
if (Entry == Head)
|
||||
return NULL;
|
||||
|
||||
return (PKSAUDIO_DEVICE_ENTRY)CONTAINING_RECORD(Entry, KSAUDIO_DEVICE_ENTRY, Entry);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SysAudioOpenVirtualDevice(
|
||||
IN PIRP Irp,
|
||||
IN ULONG DeviceNumber,
|
||||
PSYSAUDIODEVEXT DeviceExtension)
|
||||
{
|
||||
PKSAUDIO_DEVICE_ENTRY Entry;
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
|
||||
/* get current irp stack */
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
/* sanity check */
|
||||
ASSERT(IoStack->FileObject);
|
||||
|
||||
if (DeviceNumber >= DeviceExtension->NumberOfKsAudioDevices)
|
||||
{
|
||||
/* invalid device index */
|
||||
return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
|
||||
}
|
||||
|
||||
/* get device context */
|
||||
Entry = GetListEntry(&DeviceExtension->KsAudioDeviceList, DeviceNumber);
|
||||
ASSERT(Entry != NULL);
|
||||
|
||||
/* store device entry in FsContext
|
||||
* see pin.c DispatchCreateSysAudioPin for details
|
||||
*/
|
||||
IoStack->FileObject->FsContext = (PVOID)Entry;
|
||||
|
||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, 0);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
HandleSysAudioFilterPinProperties(
|
||||
PIRP Irp,
|
||||
PKSPROPERTY Property,
|
||||
PSYSAUDIODEVEXT DeviceExtension)
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
NTSTATUS Status;
|
||||
PKSAUDIO_DEVICE_ENTRY Entry;
|
||||
ULONG BytesReturned;
|
||||
PKSP_PIN Pin;
|
||||
|
||||
// in order to access pin properties of a sysaudio device
|
||||
// the caller must provide a KSP_PIN struct, where
|
||||
// Reserved member points to virtual device index
|
||||
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSP_PIN))
|
||||
{
|
||||
/* too small buffer */
|
||||
return SetIrpIoStatus(Irp, STATUS_BUFFER_TOO_SMALL, sizeof(KSPROPERTY) + sizeof(ULONG));
|
||||
}
|
||||
|
||||
Pin = (PKSP_PIN)Property;
|
||||
|
||||
Entry = GetListEntry(&DeviceExtension->KsAudioDeviceList, ((KSP_PIN*)Property)->Reserved);
|
||||
if (!Entry)
|
||||
{
|
||||
/* invalid device index */
|
||||
return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
|
||||
}
|
||||
|
||||
if (!Entry->Pins)
|
||||
{
|
||||
/* expected pins */
|
||||
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
|
||||
}
|
||||
|
||||
if (Entry->PinDescriptorsCount <= Pin->PinId)
|
||||
{
|
||||
/* invalid pin id */
|
||||
return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
|
||||
}
|
||||
|
||||
if (Property->Id == KSPROPERTY_PIN_CTYPES)
|
||||
{
|
||||
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
|
||||
{
|
||||
/* too small buffer */
|
||||
return SetIrpIoStatus(Irp, STATUS_BUFFER_TOO_SMALL, sizeof(ULONG));
|
||||
}
|
||||
/* store result */
|
||||
*((PULONG)Irp->UserBuffer) = Entry->PinDescriptorsCount;
|
||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(ULONG));
|
||||
}
|
||||
else if (Property->Id == KSPROPERTY_PIN_COMMUNICATION)
|
||||
{
|
||||
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KSPIN_COMMUNICATION))
|
||||
{
|
||||
/* too small buffer */
|
||||
return SetIrpIoStatus(Irp, STATUS_BUFFER_TOO_SMALL, sizeof(KSPIN_COMMUNICATION));
|
||||
}
|
||||
/* store result */
|
||||
*((KSPIN_COMMUNICATION*)Irp->UserBuffer) = Entry->PinDescriptors[Pin->PinId].Communication;
|
||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(KSPIN_COMMUNICATION));
|
||||
|
||||
}
|
||||
else if (Property->Id == KSPROPERTY_PIN_DATAFLOW)
|
||||
{
|
||||
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KSPIN_DATAFLOW))
|
||||
{
|
||||
/* too small buffer */
|
||||
return SetIrpIoStatus(Irp, STATUS_BUFFER_TOO_SMALL, sizeof(KSPIN_DATAFLOW));
|
||||
}
|
||||
/* store result */
|
||||
*((KSPIN_DATAFLOW*)Irp->UserBuffer) = Entry->PinDescriptors[Pin->PinId].DataFlow;
|
||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(KSPIN_DATAFLOW));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* forward request to the filter implementing the property */
|
||||
Status = KsSynchronousIoControlDevice(Entry->FileObject, KernelMode, IOCTL_KS_PROPERTY,
|
||||
(PVOID)IoStack->Parameters.DeviceIoControl.Type3InputBuffer,
|
||||
IoStack->Parameters.DeviceIoControl.InputBufferLength,
|
||||
Irp->UserBuffer,
|
||||
IoStack->Parameters.DeviceIoControl.OutputBufferLength,
|
||||
&BytesReturned);
|
||||
|
||||
return SetIrpIoStatus(Irp, Status, BytesReturned);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
ComputeCompatibleFormat(
|
||||
IN PKSAUDIO_DEVICE_ENTRY Entry,
|
||||
IN ULONG PinId,
|
||||
IN PKSDATAFORMAT_WAVEFORMATEX ClientFormat,
|
||||
OUT PKSDATAFORMAT_WAVEFORMATEX MixerFormat)
|
||||
{
|
||||
BOOL bFound;
|
||||
ULONG BytesReturned;
|
||||
PKSP_PIN PinRequest;
|
||||
NTSTATUS Status;
|
||||
PKSMULTIPLE_ITEM MultipleItem;
|
||||
ULONG Length;
|
||||
PKSDATARANGE_AUDIO AudioRange;
|
||||
ULONG Index;
|
||||
|
||||
Length = sizeof(KSP_PIN) + sizeof(KSMULTIPLE_ITEM) + ClientFormat->DataFormat.FormatSize;
|
||||
PinRequest = ExAllocatePool(NonPagedPool, Length);
|
||||
if (!PinRequest)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
|
||||
PinRequest->PinId = PinId;
|
||||
PinRequest->Property.Set = KSPROPSETID_Pin;
|
||||
PinRequest->Property.Flags = KSPROPERTY_TYPE_GET;
|
||||
PinRequest->Property.Id = KSPROPERTY_PIN_DATAINTERSECTION;
|
||||
|
||||
MultipleItem = (PKSMULTIPLE_ITEM)(PinRequest + 1);
|
||||
MultipleItem->Count = 1;
|
||||
MultipleItem->Size = ClientFormat->DataFormat.FormatSize;
|
||||
|
||||
RtlMoveMemory(MultipleItem + 1, ClientFormat, ClientFormat->DataFormat.FormatSize);
|
||||
/* Query the miniport data intersection handler */
|
||||
Status = KsSynchronousIoControlDevice(Entry->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)PinRequest, Length, (PVOID)MixerFormat, sizeof(KSDATAFORMAT_WAVEFORMATEX), &BytesReturned);
|
||||
|
||||
DPRINT("Status %x\n", Status);
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
ExFreePool(PinRequest);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Setup request block */
|
||||
PinRequest->Property.Id = KSPROPERTY_PIN_DATARANGES;
|
||||
/* Query pin data ranges */
|
||||
Status = KsSynchronousIoControlDevice(Entry->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)PinRequest, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
|
||||
|
||||
if (Status != STATUS_MORE_ENTRIES)
|
||||
{
|
||||
/* Failed to get data ranges */
|
||||
return Status;
|
||||
}
|
||||
|
||||
MultipleItem = ExAllocatePool(NonPagedPool, BytesReturned);
|
||||
if (!MultipleItem)
|
||||
{
|
||||
ExFreePool(PinRequest);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
Status = KsSynchronousIoControlDevice(Entry->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)PinRequest, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Property Request KSPROPERTY_PIN_DATARANGES failed with %x\n", Status);
|
||||
ExFreePool(MultipleItem);
|
||||
ExFreePool(PinRequest);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
AudioRange = (PKSDATARANGE_AUDIO)(MultipleItem + 1);
|
||||
bFound = FALSE;
|
||||
for(Index = 0; Index < MultipleItem->Count; Index++)
|
||||
{
|
||||
if (AudioRange->DataRange.FormatSize != sizeof(KSDATARANGE_AUDIO))
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
AudioRange = (PKSDATARANGE_AUDIO)((PUCHAR)AudioRange + AudioRange->DataRange.FormatSize);
|
||||
continue;
|
||||
}
|
||||
/* Select best quality available */
|
||||
|
||||
MixerFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
|
||||
MixerFormat->DataFormat.Flags = 0;
|
||||
MixerFormat->DataFormat.Reserved = 0;
|
||||
MixerFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
|
||||
MixerFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
MixerFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
|
||||
MixerFormat->DataFormat.SampleSize = 4;
|
||||
MixerFormat->WaveFormatEx.wFormatTag = ClientFormat->WaveFormatEx.wFormatTag;
|
||||
#ifndef NO_AC97_HACK
|
||||
/* HACK: AC97 does not support mono render / record */
|
||||
MixerFormat->WaveFormatEx.nChannels = 2;
|
||||
/*HACK: AC97 only supports 16-Bit Bits */
|
||||
MixerFormat->WaveFormatEx.wBitsPerSample = 16;
|
||||
|
||||
#else
|
||||
MixerFormat->WaveFormatEx.nChannels = min(ClientFormat->WaveFormatEx.nChannels, AudioRange->MaximumChannels);
|
||||
MixerFormat->WaveFormatEx.wBitsPerSample = AudioRange->MaximumBitsPerSample;
|
||||
#endif
|
||||
|
||||
#ifdef KMIXER_RESAMPLING_IMPLEMENTED
|
||||
MixerFormat->WaveFormatEx.nSamplesPerSec = AudioRange->MaximumSampleFrequency;
|
||||
#else
|
||||
MixerFormat->WaveFormatEx.nSamplesPerSec = max(AudioRange->MinimumSampleFrequency, min(ClientFormat->WaveFormatEx.nSamplesPerSec, AudioRange->MaximumSampleFrequency));
|
||||
#endif
|
||||
|
||||
MixerFormat->WaveFormatEx.cbSize = 0;
|
||||
MixerFormat->WaveFormatEx.nBlockAlign = (MixerFormat->WaveFormatEx.nChannels * MixerFormat->WaveFormatEx.wBitsPerSample) / 8;
|
||||
MixerFormat->WaveFormatEx.nAvgBytesPerSec = MixerFormat->WaveFormatEx.nChannels * MixerFormat->WaveFormatEx.nSamplesPerSec * (MixerFormat->WaveFormatEx.wBitsPerSample / 8);
|
||||
|
||||
bFound = TRUE;
|
||||
break;
|
||||
|
||||
AudioRange = (PKSDATARANGE_AUDIO)((PUCHAR)AudioRange + AudioRange->DataRange.FormatSize);
|
||||
}
|
||||
|
||||
#if 0
|
||||
DPRINT1("\nNum Max Channels %u Channels %u Old Channels %u\n Max SampleRate %u SampleRate %u Old SampleRate %u\n Max BitsPerSample %u BitsPerSample %u Old BitsPerSample %u\n",
|
||||
AudioRange->MaximumChannels, MixerFormat->WaveFormatEx.nChannels, ClientFormat->WaveFormatEx.nChannels,
|
||||
AudioRange->MaximumSampleFrequency, MixerFormat->WaveFormatEx.nSamplesPerSec, ClientFormat->WaveFormatEx.nSamplesPerSec,
|
||||
AudioRange->MaximumBitsPerSample, MixerFormat->WaveFormatEx.wBitsPerSample, ClientFormat->WaveFormatEx.wBitsPerSample);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
ExFreePool(MultipleItem);
|
||||
ExFreePool(PinRequest);
|
||||
|
||||
if (bFound)
|
||||
return STATUS_SUCCESS;
|
||||
else
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
GetPinInstanceCount(
|
||||
PKSAUDIO_DEVICE_ENTRY Entry,
|
||||
PKSPIN_CINSTANCES PinInstances,
|
||||
PKSPIN_CONNECT PinConnect)
|
||||
{
|
||||
KSP_PIN PinRequest;
|
||||
ULONG BytesReturned;
|
||||
|
||||
/* query the instance count */
|
||||
PinRequest.PinId = PinConnect->PinId;
|
||||
PinRequest.Property.Set = KSPROPSETID_Pin;
|
||||
PinRequest.Property.Flags = KSPROPERTY_TYPE_GET;
|
||||
PinRequest.Property.Id = KSPROPERTY_PIN_CINSTANCES;
|
||||
|
||||
return KsSynchronousIoControlDevice(Entry->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinRequest, sizeof(KSP_PIN), (PVOID)PinInstances, sizeof(KSPIN_CINSTANCES), &BytesReturned);
|
||||
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SysAudioHandleProperty(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
|
||||
KSPROPERTY PropertyRequest;
|
||||
KSCOMPONENTID ComponentId;
|
||||
PULONG Index;
|
||||
PKSPROPERTY Property;
|
||||
PSYSAUDIODEVEXT DeviceExtension;
|
||||
PKSAUDIO_DEVICE_ENTRY Entry;
|
||||
PSYSAUDIO_INSTANCE_INFO InstanceInfo;
|
||||
ULONG BytesReturned;
|
||||
PKSOBJECT_CREATE_ITEM CreateItem;
|
||||
UNICODE_STRING GuidString;
|
||||
PKSP_PIN Pin;
|
||||
LPWSTR DeviceName;
|
||||
|
||||
/* access the create item */
|
||||
CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
||||
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSPROPERTY))
|
||||
{
|
||||
/* buffer must be at least of sizeof KSPROPERTY */
|
||||
return SetIrpIoStatus(Irp, STATUS_BUFFER_TOO_SMALL, sizeof(KSPROPERTY));
|
||||
}
|
||||
|
||||
Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
|
||||
DeviceExtension = (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension;
|
||||
|
||||
if (IsEqualGUIDAligned(&Property->Set, &KSPROPSETID_Pin))
|
||||
{
|
||||
return HandleSysAudioFilterPinProperties(Irp, Property, DeviceExtension);
|
||||
}
|
||||
else if(IsEqualGUIDAligned(&Property->Set, &KSPROPSETID_Topology))
|
||||
{
|
||||
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSP_PIN))
|
||||
{
|
||||
/* too small buffer */
|
||||
return SetIrpIoStatus(Irp, STATUS_BUFFER_TOO_SMALL, sizeof(KSP_PIN));
|
||||
}
|
||||
Pin = (PKSP_PIN)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
|
||||
Entry = GetListEntry(&DeviceExtension->KsAudioDeviceList, Pin->Reserved);
|
||||
ASSERT(Entry != NULL);
|
||||
|
||||
/* forward request to the filter implementing the property */
|
||||
Status = KsSynchronousIoControlDevice(Entry->FileObject, KernelMode, IOCTL_KS_PROPERTY,
|
||||
(PVOID)IoStack->Parameters.DeviceIoControl.Type3InputBuffer,
|
||||
IoStack->Parameters.DeviceIoControl.InputBufferLength,
|
||||
Irp->UserBuffer,
|
||||
IoStack->Parameters.DeviceIoControl.OutputBufferLength,
|
||||
&BytesReturned);
|
||||
|
||||
return SetIrpIoStatus(Irp, Status, BytesReturned);
|
||||
}
|
||||
else if (IsEqualGUIDAligned(&Property->Set, &KSPROPSETID_Sysaudio))
|
||||
{
|
||||
if (Property->Id == KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME)
|
||||
{
|
||||
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSPROPERTY) + sizeof(ULONG))
|
||||
{
|
||||
/* invalid request */
|
||||
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, sizeof(KSPROPERTY) + sizeof(ULONG));
|
||||
}
|
||||
Index = (PULONG)(Property + 1);
|
||||
|
||||
if (DeviceExtension->NumberOfKsAudioDevices <= *Index)
|
||||
{
|
||||
/* invalid index */
|
||||
return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
|
||||
}
|
||||
|
||||
Entry = GetListEntry(&DeviceExtension->KsAudioDeviceList, *Index);
|
||||
ASSERT(Entry != NULL);
|
||||
|
||||
BytesReturned = Entry->DeviceName.Length + sizeof(WCHAR);
|
||||
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < BytesReturned)
|
||||
{
|
||||
/* too small buffer */
|
||||
return SetIrpIoStatus(Irp, STATUS_BUFFER_TOO_SMALL, BytesReturned);
|
||||
}
|
||||
|
||||
/* copy device name */
|
||||
DeviceName = (LPWSTR)Irp->UserBuffer;
|
||||
|
||||
RtlMoveMemory(DeviceName, Entry->DeviceName.Buffer, Entry->DeviceName.Length);
|
||||
DeviceName[Entry->DeviceName.Length / sizeof(WCHAR)] = L'\0';
|
||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, BytesReturned);
|
||||
}
|
||||
|
||||
if (Property->Id == KSPROPERTY_SYSAUDIO_COMPONENT_ID)
|
||||
{
|
||||
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSPROPERTY) + sizeof(ULONG))
|
||||
{
|
||||
/* too small buffer */
|
||||
return SetIrpIoStatus(Irp, STATUS_BUFFER_TOO_SMALL, sizeof(KSPROPERTY) + sizeof(ULONG));
|
||||
}
|
||||
|
||||
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KSCOMPONENTID))
|
||||
{
|
||||
/* too small buffer */
|
||||
return SetIrpIoStatus(Irp, STATUS_BUFFER_TOO_SMALL, sizeof(KSCOMPONENTID));
|
||||
}
|
||||
|
||||
Index = (PULONG)(Property + 1);
|
||||
|
||||
if (DeviceExtension->NumberOfKsAudioDevices <= *Index)
|
||||
{
|
||||
/* invalid index */
|
||||
return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
|
||||
}
|
||||
Entry = GetListEntry(&DeviceExtension->KsAudioDeviceList, *Index);
|
||||
ASSERT(Entry != NULL);
|
||||
|
||||
PropertyRequest.Set = KSPROPSETID_General;
|
||||
PropertyRequest.Id = KSPROPERTY_GENERAL_COMPONENTID;
|
||||
PropertyRequest.Flags = KSPROPERTY_TYPE_GET;
|
||||
|
||||
/* call the filter */
|
||||
Status = KsSynchronousIoControlDevice(Entry->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PropertyRequest, sizeof(KSPROPERTY), (PVOID)&ComponentId, sizeof(KSCOMPONENTID), &BytesReturned);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("KsSynchronousIoControlDevice failed with %x for KSPROPERTY_GENERAL_COMPONENTID\n", Status);
|
||||
return SetIrpIoStatus(Irp, Status, 0);
|
||||
}
|
||||
RtlMoveMemory(Irp->UserBuffer, &ComponentId, sizeof(KSCOMPONENTID));
|
||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(KSCOMPONENTID));
|
||||
}
|
||||
else if (Property->Id == KSPROPERTY_SYSAUDIO_DEVICE_COUNT)
|
||||
{
|
||||
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
|
||||
{
|
||||
/* too small buffer */
|
||||
return SetIrpIoStatus(Irp, STATUS_BUFFER_TOO_SMALL, sizeof(ULONG));
|
||||
}
|
||||
|
||||
*((PULONG)Irp->UserBuffer) = DeviceExtension->NumberOfKsAudioDevices;
|
||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(ULONG));
|
||||
}
|
||||
else if (Property->Id == KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE)
|
||||
{
|
||||
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
|
||||
{
|
||||
/* too small buffer */
|
||||
return SetIrpIoStatus(Irp, STATUS_BUFFER_TOO_SMALL, sizeof(ULONG));
|
||||
}
|
||||
|
||||
if (Property->Flags & KSPROPERTY_TYPE_SET)
|
||||
{
|
||||
Index = (PULONG)Irp->UserBuffer;
|
||||
return SysAudioOpenVirtualDevice(Irp, *Index, DeviceExtension);
|
||||
}
|
||||
}
|
||||
else if (Property->Id == KSPROPERTY_SYSAUDIO_INSTANCE_INFO)
|
||||
{
|
||||
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SYSAUDIO_INSTANCE_INFO))
|
||||
{
|
||||
/* too small buffer */
|
||||
return SetIrpIoStatus(Irp, STATUS_BUFFER_TOO_SMALL, sizeof(SYSAUDIO_INSTANCE_INFO));
|
||||
}
|
||||
|
||||
/* get input parameter */
|
||||
InstanceInfo = (PSYSAUDIO_INSTANCE_INFO)Property;
|
||||
|
||||
if (Property->Flags & KSPROPERTY_TYPE_SET)
|
||||
{
|
||||
return SysAudioOpenVirtualDevice(Irp, InstanceInfo->DeviceNumber, DeviceExtension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RtlStringFromGUID(&Property->Set, &GuidString);
|
||||
DPRINT1("Unhandeled property Set |%S| Id %u Flags %x\n", GuidString.Buffer, Property->Id, Property->Flags);
|
||||
RtlFreeUnicodeString(&GuidString);
|
||||
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
|
||||
}
|
419
drivers/wdm/audio/sysaudio/deviface.c
Normal file
419
drivers/wdm/audio/sysaudio/deviface.c
Normal file
|
@ -0,0 +1,419 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel Streaming
|
||||
* FILE: drivers/wdm/audio/sysaudio/deviface.c
|
||||
* PURPOSE: System Audio graph builder
|
||||
* PROGRAMMER: Johannes Anderwald
|
||||
*/
|
||||
|
||||
#include "sysaudio.h"
|
||||
|
||||
const GUID GUID_DEVICE_INTERFACE_ARRIVAL = {0xCB3A4004L, 0x46F0, 0x11D0, {0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F}};
|
||||
const GUID GUID_DEVICE_INTERFACE_REMOVAL = {0xCB3A4005L, 0x46F0, 0x11D0, {0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F}};
|
||||
const GUID KS_CATEGORY_AUDIO = {0x6994AD04L, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
|
||||
const GUID KS_CATEGORY_TOPOLOGY = {0xDDA54A40, 0x1E4C, 0x11D1, {0xA0, 0x50, 0x40, 0x57, 0x05, 0xC1, 0x00, 0x00}};
|
||||
const GUID DMOCATEGORY_ACOUSTIC_ECHO_CANCEL = {0xBF963D80L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
|
||||
|
||||
NTSTATUS
|
||||
BuildPinDescriptor(
|
||||
IN PKSAUDIO_DEVICE_ENTRY DeviceEntry,
|
||||
IN ULONG Count)
|
||||
{
|
||||
ULONG Index;
|
||||
KSP_PIN PinRequest;
|
||||
KSPIN_DATAFLOW DataFlow;
|
||||
KSPIN_COMMUNICATION Communication;
|
||||
ULONG NumWaveOutPin, NumWaveInPin;
|
||||
NTSTATUS Status;
|
||||
ULONG BytesReturned;
|
||||
|
||||
NumWaveInPin = 0;
|
||||
NumWaveOutPin = 0;
|
||||
for(Index = 0; Index < Count; Index++)
|
||||
{
|
||||
/* retrieve data flow */
|
||||
PinRequest.PinId = Index;
|
||||
PinRequest.Property.Set = KSPROPSETID_Pin;
|
||||
PinRequest.Property.Flags = KSPROPERTY_TYPE_GET;
|
||||
|
||||
/* get dataflow direction */
|
||||
PinRequest.Property.Id = KSPROPERTY_PIN_DATAFLOW;
|
||||
Status = KsSynchronousIoControlDevice(DeviceEntry->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinRequest, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
DeviceEntry->PinDescriptors[Index].DataFlow = DataFlow;
|
||||
}
|
||||
|
||||
/* get irp flow direction */
|
||||
PinRequest.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
|
||||
Status = KsSynchronousIoControlDevice(DeviceEntry->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinRequest, sizeof(KSP_PIN), (PVOID)&Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
DeviceEntry->PinDescriptors[Index].Communication = Communication;
|
||||
}
|
||||
|
||||
if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
|
||||
NumWaveOutPin++;
|
||||
|
||||
if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
|
||||
NumWaveInPin++;
|
||||
|
||||
/* FIXME query for interface, dataformat etc */
|
||||
}
|
||||
|
||||
DPRINT("Num Pins %u Num WaveIn Pins %u Name WaveOut Pins %u\n", DeviceEntry->PinDescriptorsCount, NumWaveInPin, NumWaveOutPin);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
QueryFilterRoutine(
|
||||
IN PKSAUDIO_DEVICE_ENTRY DeviceEntry)
|
||||
{
|
||||
KSPROPERTY PropertyRequest;
|
||||
ULONG Count;
|
||||
NTSTATUS Status;
|
||||
ULONG BytesReturned;
|
||||
|
||||
DPRINT("Querying filter...\n");
|
||||
|
||||
PropertyRequest.Set = KSPROPSETID_Pin;
|
||||
PropertyRequest.Flags = KSPROPERTY_TYPE_GET;
|
||||
PropertyRequest.Id = KSPROPERTY_PIN_CTYPES;
|
||||
|
||||
/* query for num of pins */
|
||||
Status = KsSynchronousIoControlDevice(DeviceEntry->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PropertyRequest, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to query number of pins Status %x\n", Status);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Count)
|
||||
{
|
||||
DPRINT1("Filter has no pins!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* allocate pin descriptor array */
|
||||
DeviceEntry->PinDescriptors = ExAllocatePool(NonPagedPool, Count * sizeof(KSPIN_DESCRIPTOR));
|
||||
if (!DeviceEntry->PinDescriptors)
|
||||
{
|
||||
/* no memory */
|
||||
return;
|
||||
}
|
||||
|
||||
/* zero array pin descriptor array */
|
||||
RtlZeroMemory(DeviceEntry->PinDescriptors, Count * sizeof(KSPIN_DESCRIPTOR));
|
||||
|
||||
/* build the device descriptor */
|
||||
Status = BuildPinDescriptor(DeviceEntry, Count);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return;
|
||||
|
||||
|
||||
/* allocate pin array */
|
||||
DeviceEntry->Pins = ExAllocatePool(NonPagedPool, Count * sizeof(PIN_INFO));
|
||||
if (!DeviceEntry->Pins)
|
||||
{
|
||||
/* no memory */
|
||||
DPRINT1("Failed to allocate memory Pins %u Block %x\n", Count, Count * sizeof(PIN_INFO));
|
||||
return;
|
||||
}
|
||||
|
||||
/* clear array */
|
||||
RtlZeroMemory(DeviceEntry->Pins, sizeof(PIN_INFO) * Count);
|
||||
DeviceEntry->PinDescriptorsCount = Count;
|
||||
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
FilterPinWorkerRoutine(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PVOID Context)
|
||||
{
|
||||
PKSAUDIO_DEVICE_ENTRY DeviceEntry;
|
||||
PFILTER_WORKER_CONTEXT Ctx = (PFILTER_WORKER_CONTEXT)Context;
|
||||
|
||||
DeviceEntry = Ctx->DeviceEntry;
|
||||
|
||||
QueryFilterRoutine(DeviceEntry);
|
||||
|
||||
/* free work item */
|
||||
IoFreeWorkItem(Ctx->WorkItem);
|
||||
/* free work item context */
|
||||
ExFreePool(Ctx);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
OpenDevice(
|
||||
IN PUNICODE_STRING DeviceName,
|
||||
IN PHANDLE HandleOut,
|
||||
IN PFILE_OBJECT * FileObjectOut)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HANDLE NodeHandle;
|
||||
PFILE_OBJECT FileObject;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttributes, DeviceName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||
|
||||
Status = ZwCreateFile(&NodeHandle,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
FILE_OPEN,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("ZwCreateFile failed with %x %S\n", Status, DeviceName->Buffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = ObReferenceObjectByHandle(NodeHandle, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ZwClose(NodeHandle);
|
||||
DPRINT("ObReferenceObjectByHandle failed with %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
*HandleOut = NodeHandle;
|
||||
*FileObjectOut = FileObject;
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
InsertAudioDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PUNICODE_STRING DeviceName)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PFILTER_WORKER_CONTEXT Ctx = NULL;
|
||||
PIO_WORKITEM WorkItem = NULL;
|
||||
PSYSAUDIODEVEXT DeviceExtension;
|
||||
PKSAUDIO_DEVICE_ENTRY DeviceEntry = NULL;
|
||||
|
||||
/* a new device has arrived */
|
||||
DeviceEntry = ExAllocatePool(NonPagedPool, sizeof(KSAUDIO_DEVICE_ENTRY));
|
||||
if (!DeviceEntry)
|
||||
{
|
||||
/* no memory */
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* initialize audio device entry */
|
||||
RtlZeroMemory(DeviceEntry, sizeof(KSAUDIO_DEVICE_ENTRY));
|
||||
|
||||
/* allocate filter ctx */
|
||||
Ctx = ExAllocatePool(NonPagedPool, sizeof(FILTER_WORKER_CONTEXT));
|
||||
if (!Ctx)
|
||||
{
|
||||
/* no memory */
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* allocate work item */
|
||||
WorkItem = IoAllocateWorkItem(DeviceObject);
|
||||
if (!WorkItem)
|
||||
{
|
||||
/* no memory */
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* set device name */
|
||||
DeviceEntry->DeviceName.Length = 0;
|
||||
DeviceEntry->DeviceName.MaximumLength = DeviceName->MaximumLength + 10 * sizeof(WCHAR);
|
||||
|
||||
DeviceEntry->DeviceName.Buffer = ExAllocatePool(NonPagedPool, DeviceEntry->DeviceName.MaximumLength);
|
||||
|
||||
if (!DeviceEntry->DeviceName.Buffer)
|
||||
{
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
RtlAppendUnicodeToString(&DeviceEntry->DeviceName, L"\\??\\");
|
||||
RtlAppendUnicodeStringToString(&DeviceEntry->DeviceName, DeviceName);
|
||||
|
||||
Status = OpenDevice(&DeviceEntry->DeviceName, &DeviceEntry->Handle, &DeviceEntry->FileObject);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
Ctx->DeviceEntry = DeviceEntry;
|
||||
Ctx->WorkItem = WorkItem;
|
||||
|
||||
/* fetch device extension */
|
||||
DeviceExtension = (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension;
|
||||
/* insert new audio device */
|
||||
ExInterlockedInsertTailList(&DeviceExtension->KsAudioDeviceList, &DeviceEntry->Entry, &DeviceExtension->Lock);
|
||||
InterlockedIncrement((PLONG)&DeviceExtension->NumberOfKsAudioDevices);
|
||||
|
||||
DPRINT("Successfully opened audio device %u Device %S\n", DeviceExtension->NumberOfKsAudioDevices, DeviceEntry->DeviceName.Buffer);
|
||||
IoQueueWorkItem(WorkItem, FilterPinWorkerRoutine, DelayedWorkQueue, (PVOID)Ctx);
|
||||
return Status;
|
||||
|
||||
cleanup:
|
||||
if (Ctx)
|
||||
ExFreePool(Ctx);
|
||||
|
||||
if (WorkItem)
|
||||
IoFreeWorkItem(WorkItem);
|
||||
|
||||
if (DeviceEntry)
|
||||
{
|
||||
if (DeviceEntry->DeviceName.Buffer)
|
||||
ExFreePool(DeviceEntry->DeviceName.Buffer);
|
||||
|
||||
ExFreePool(DeviceEntry);
|
||||
}
|
||||
|
||||
return Status;
|
||||
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
DeviceInterfaceChangeCallback(
|
||||
IN PVOID NotificationStructure,
|
||||
IN PVOID Context)
|
||||
{
|
||||
DEVICE_INTERFACE_CHANGE_NOTIFICATION * Event;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PSYSAUDIODEVEXT DeviceExtension;
|
||||
PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
|
||||
|
||||
DeviceExtension = (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension;
|
||||
|
||||
Event = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure;
|
||||
|
||||
if (IsEqualGUIDAligned(&Event->Event,
|
||||
&GUID_DEVICE_INTERFACE_ARRIVAL))
|
||||
{
|
||||
Status = InsertAudioDevice(DeviceObject, Event->SymbolicLinkName);
|
||||
return Status;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Remove interface to audio device!\n");
|
||||
UNIMPLEMENTED
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SysAudioRegisterNotifications(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PSYSAUDIODEVEXT DeviceExtension;
|
||||
|
||||
DeviceExtension = (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension;
|
||||
|
||||
Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
|
||||
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
|
||||
(PVOID)&KS_CATEGORY_AUDIO,
|
||||
DriverObject,
|
||||
DeviceInterfaceChangeCallback,
|
||||
(PVOID)DeviceObject,
|
||||
(PVOID*)&DeviceExtension->KsAudioNotificationEntry);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("IoRegisterPlugPlayNotification failed with %x\n", Status);
|
||||
}
|
||||
|
||||
Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
|
||||
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
|
||||
(PVOID)&DMOCATEGORY_ACOUSTIC_ECHO_CANCEL,
|
||||
DriverObject,
|
||||
DeviceInterfaceChangeCallback,
|
||||
(PVOID)DeviceObject,
|
||||
(PVOID*)&DeviceExtension->EchoCancelNotificationEntry);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* ignore failure for now */
|
||||
DPRINT("IoRegisterPlugPlayNotification failed for DMOCATEGORY_ACOUSTIC_ECHO_CANCEL\n", Status);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NTSTATUS
|
||||
SysAudioRegisterDeviceInterfaces(
|
||||
IN PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING SymbolicLink;
|
||||
|
||||
Status = IoRegisterDeviceInterface(DeviceObject, &KSCATEGORY_PREFERRED_MIDIOUT_DEVICE, NULL, &SymbolicLink);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
IoSetDeviceInterfaceState(&SymbolicLink, TRUE);
|
||||
RtlFreeUnicodeString(&SymbolicLink);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Failed to register KSCATEGORY_PREFERRED_MIDIOUT_DEVICE interface Status %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = IoRegisterDeviceInterface(DeviceObject, &KSCATEGORY_PREFERRED_WAVEIN_DEVICE, NULL, &SymbolicLink);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
IoSetDeviceInterfaceState(&SymbolicLink, TRUE);
|
||||
RtlFreeUnicodeString(&SymbolicLink);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Failed to register KSCATEGORY_PREFERRED_WAVEIN_DEVICE interface Status %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = IoRegisterDeviceInterface(DeviceObject, &KSCATEGORY_PREFERRED_WAVEOUT_DEVICE, NULL, &SymbolicLink);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
IoSetDeviceInterfaceState(&SymbolicLink, TRUE);
|
||||
RtlFreeUnicodeString(&SymbolicLink);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Failed to register KSCATEGORY_PREFERRED_WAVEOUT_DEVICE interface Status %x\n", Status);
|
||||
}
|
||||
|
||||
Status = IoRegisterDeviceInterface(DeviceObject, &KSCATEGORY_SYSAUDIO, NULL, &SymbolicLink);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
IoSetDeviceInterfaceState(&SymbolicLink, TRUE);
|
||||
RtlFreeUnicodeString(&SymbolicLink);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Failed to register KSCATEGORY_SYSAUDIO interface Status %x\n", Status);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
150
drivers/wdm/audio/sysaudio/dispatcher.c
Normal file
150
drivers/wdm/audio/sysaudio/dispatcher.c
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel Streaming
|
||||
* FILE: drivers/wdm/audio/sysaudio/dispatcher.c
|
||||
* PURPOSE: System Audio graph builder
|
||||
* PROGRAMMER: Johannes Anderwald
|
||||
*/
|
||||
|
||||
#include "sysaudio.h"
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
Dispatch_fnDeviceIoControl(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KS_PROPERTY)
|
||||
{
|
||||
return SysAudioHandleProperty(DeviceObject, Irp);
|
||||
}
|
||||
|
||||
/* unsupported request */
|
||||
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
||||
Irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
Dispatch_fnClose(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp)
|
||||
{
|
||||
DPRINT("Dispatch_fnClose called DeviceObject %p Irp %p\n", DeviceObject);
|
||||
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
Irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static KSDISPATCH_TABLE DispatchTable =
|
||||
{
|
||||
Dispatch_fnDeviceIoControl,
|
||||
KsDispatchInvalidDeviceRequest,
|
||||
KsDispatchInvalidDeviceRequest,
|
||||
KsDispatchInvalidDeviceRequest,
|
||||
Dispatch_fnClose,
|
||||
KsDispatchInvalidDeviceRequest,
|
||||
KsDispatchInvalidDeviceRequest,
|
||||
KsDispatchFastIoDeviceControlFailure,
|
||||
KsDispatchFastReadFailure,
|
||||
KsDispatchFastWriteFailure,
|
||||
};
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
DispatchCreateSysAudio(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
KSOBJECT_HEADER ObjectHeader;
|
||||
PKSOBJECT_CREATE_ITEM CreateItem;
|
||||
|
||||
DPRINT("DispatchCreateSysAudio entered\n");
|
||||
|
||||
/* allocate create item */
|
||||
CreateItem = ExAllocatePool(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM));
|
||||
if (!CreateItem)
|
||||
{
|
||||
Irp->IoStatus.Information = 0;
|
||||
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* zero create struct */
|
||||
RtlZeroMemory(CreateItem, sizeof(KSOBJECT_CREATE_ITEM));
|
||||
|
||||
/* setup create context */
|
||||
CreateItem->Create = DispatchCreateSysAudioPin;
|
||||
RtlInitUnicodeString(&CreateItem->ObjectClass, KSSTRING_Pin);
|
||||
|
||||
/* allocate object header */
|
||||
Status = KsAllocateObjectHeader(&ObjectHeader, 1, CreateItem, Irp, &DispatchTable);
|
||||
|
||||
DPRINT("KsAllocateObjectHeader result %x\n", Status);
|
||||
/* complete the irp */
|
||||
Irp->IoStatus.Information = 0;
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SysAudioAllocateDeviceHeader(
|
||||
IN SYSAUDIODEVEXT *DeviceExtension)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PKSOBJECT_CREATE_ITEM CreateItem;
|
||||
|
||||
/* allocate create item */
|
||||
CreateItem = ExAllocatePool(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM));
|
||||
if (!CreateItem)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
/* initialize create item struct */
|
||||
RtlZeroMemory(CreateItem, sizeof(KSOBJECT_CREATE_ITEM));
|
||||
CreateItem->Create = DispatchCreateSysAudio;
|
||||
|
||||
/* FIXME Sysaudio doesnt need a named create item because it installs itself
|
||||
* via the device interface
|
||||
*/
|
||||
RtlInitUnicodeString(&CreateItem->ObjectClass, L"GLOBAL");
|
||||
CreateItem->Flags = KSCREATE_ITEM_WILDCARD;
|
||||
|
||||
Status = KsAllocateDeviceHeader(&DeviceExtension->KsDeviceHeader,
|
||||
1,
|
||||
CreateItem);
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SysAudioOpenKMixer(
|
||||
IN SYSAUDIODEVEXT *DeviceExtension)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING DeviceInstanceName = RTL_CONSTANT_STRING(L"\\Device\\kmixer\\GLOBAL");
|
||||
UNICODE_STRING DevicePath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\kmixer");
|
||||
|
||||
Status = ZwLoadDriver(&DevicePath);
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
Status = OpenDevice(&DeviceInstanceName, &DeviceExtension->KMixerHandle, &DeviceExtension->KMixerFileObject);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DeviceExtension->KMixerHandle = NULL;
|
||||
DeviceExtension->KMixerFileObject = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINT("Status %lx KMixerHandle %p KMixerFileObject %p\n", Status, DeviceExtension->KMixerHandle, DeviceExtension->KMixerFileObject);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
244
drivers/wdm/audio/sysaudio/main.c
Normal file
244
drivers/wdm/audio/sysaudio/main.c
Normal file
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel Streaming
|
||||
* FILE: drivers/wdm/audio/sysaudio/main.c
|
||||
* PURPOSE: System Audio graph builder
|
||||
* PROGRAMMER: Andrew Greenwood
|
||||
* Johannes Anderwald
|
||||
* HISTORY:
|
||||
* 8 Jul 07 Started basic implementation
|
||||
*/
|
||||
|
||||
#include "sysaudio.h"
|
||||
|
||||
|
||||
const GUID KSCATEGORY_SYSAUDIO = {0xA7C7A5B1L, 0x5AF3, 0x11D1, {0x9C, 0xED, 0x00, 0xA0, 0x24, 0xBF, 0x04, 0x07}};
|
||||
const GUID KSCATEGORY_AUDIO_DEVICE = {0xFBF6F530L, 0x07B9, 0x11D2, {0xA7, 0x1E, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}};
|
||||
const GUID KSCATEGORY_PREFERRED_WAVEOUT_DEVICE = {0xD6C5066EL, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}};
|
||||
const GUID KSCATEGORY_PREFERRED_WAVEIN_DEVICE = {0xD6C50671L, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}};
|
||||
const GUID KSCATEGORY_PREFERRED_MIDIOUT_DEVICE = {0xD6C50674L, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}};
|
||||
|
||||
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
SysAudio_Unload(IN PDRIVER_OBJECT DriverObject)
|
||||
{
|
||||
DPRINT("SysAudio_Unload called\n");
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
SysAudio_Shutdown(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PKSAUDIO_DEVICE_ENTRY DeviceEntry;
|
||||
PSYSAUDIODEVEXT DeviceExtension;
|
||||
PLIST_ENTRY Entry;
|
||||
|
||||
DPRINT("SysAudio_Shutdown called\n");
|
||||
|
||||
DeviceExtension = (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension;
|
||||
|
||||
while(!IsListEmpty(&DeviceExtension->KsAudioDeviceList))
|
||||
{
|
||||
Entry = RemoveHeadList(&DeviceExtension->KsAudioDeviceList);
|
||||
DeviceEntry = (PKSAUDIO_DEVICE_ENTRY)CONTAINING_RECORD(Entry, KSAUDIO_DEVICE_ENTRY, Entry);
|
||||
|
||||
DPRINT("Freeing item %wZ\n", &DeviceEntry->DeviceName);
|
||||
|
||||
/* dereference audio device file object */
|
||||
ObDereferenceObject(DeviceEntry->FileObject);
|
||||
|
||||
/* close audio device handle */
|
||||
ZwClose(DeviceEntry->Handle);
|
||||
/* free device string */
|
||||
RtlFreeUnicodeString(&DeviceEntry->DeviceName);
|
||||
/* free pins */
|
||||
ExFreePool(DeviceEntry->Pins);
|
||||
/* free audio device entry */
|
||||
ExFreePool(DeviceEntry);
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = 0;
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
SysAudio_Pnp(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IrpStack;
|
||||
UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\sysaudio");
|
||||
SYSAUDIODEVEXT *DeviceExtension;
|
||||
|
||||
/* Get current irp stack */
|
||||
IrpStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
/* Fetch the device extension */
|
||||
DeviceExtension = (SYSAUDIODEVEXT*)DeviceObject->DeviceExtension;
|
||||
ASSERT(DeviceExtension);
|
||||
|
||||
if (IrpStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
|
||||
{
|
||||
/* Unregister the echo cancel hook */
|
||||
if (DeviceExtension->EchoCancelNotificationEntry)
|
||||
IoUnregisterPlugPlayNotification(DeviceExtension->EchoCancelNotificationEntry);
|
||||
|
||||
/* Unregister the ks audio hook */
|
||||
if (DeviceExtension->KsAudioNotificationEntry)
|
||||
IoUnregisterPlugPlayNotification(DeviceExtension->KsAudioNotificationEntry);
|
||||
|
||||
/* Destroy our symbolic link */
|
||||
IoDeleteSymbolicLink(&SymlinkName);
|
||||
}
|
||||
else if (IrpStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
|
||||
{
|
||||
/* Sysaudio can not be disabled */
|
||||
Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
|
||||
}
|
||||
|
||||
/* Perform default pnp actions */
|
||||
return KsDefaultDispatchPnp(DeviceObject, Irp);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
SysAudio_InstallDevice(
|
||||
IN PDRIVER_OBJECT DriverObject)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\sysaudio");
|
||||
UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\sysaudio");
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
SYSAUDIODEVEXT *DeviceExtension;
|
||||
|
||||
|
||||
DPRINT("SysAudio_InstallDevice called\n");
|
||||
|
||||
/* Create the device */
|
||||
Status = IoCreateDevice(DriverObject,
|
||||
sizeof(SYSAUDIODEVEXT),
|
||||
&DeviceName,
|
||||
FILE_DEVICE_KS,
|
||||
0,
|
||||
FALSE,
|
||||
&DeviceObject);
|
||||
|
||||
/* Check for success */
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Failed to create \\Device\\sysaudio !\n");
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Register device interfaces */
|
||||
Status = SysAudioRegisterDeviceInterfaces(DeviceObject);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Failed to register
|
||||
* Create a hack interface
|
||||
*/
|
||||
Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
IoDeleteDevice(DeviceObject);
|
||||
DPRINT1("Failed to create sysaudio symlink!\n");
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
/* Acquire device extension */
|
||||
DeviceExtension = (SYSAUDIODEVEXT*)DeviceObject->DeviceExtension;
|
||||
/* Initialize device extension */
|
||||
RtlZeroMemory(DeviceExtension, sizeof(SYSAUDIODEVEXT));
|
||||
|
||||
/* Initialize the mutex */
|
||||
KeInitializeSpinLock(&DeviceExtension->Lock);
|
||||
|
||||
/* Initialize the ks audio device list */
|
||||
InitializeListHead(&DeviceExtension->KsAudioDeviceList);
|
||||
|
||||
/* Allocate kernel streaming device header */
|
||||
Status = SysAudioAllocateDeviceHeader(DeviceExtension);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("KsAllocateDeviceHeader failed with %x\n", Status);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Register device notification hooks */
|
||||
Status = SysAudioRegisterNotifications(DriverObject,
|
||||
DeviceObject);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to register device notifications\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Load kmixer */
|
||||
Status = SysAudioOpenKMixer(DeviceExtension);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("SysAudioOpenKMixer failed with %x\n", Status);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* set io flags */
|
||||
DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
|
||||
/* clear initializing flag */
|
||||
DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
|
||||
|
||||
/* register shutdown notfication */
|
||||
IoRegisterShutdownNotification(DeviceObject);
|
||||
|
||||
|
||||
/* Done */
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
|
||||
if (DeviceExtension->KsAudioNotificationEntry)
|
||||
IoUnregisterPlugPlayNotification(DeviceExtension->KsAudioNotificationEntry);
|
||||
|
||||
if (DeviceExtension->EchoCancelNotificationEntry)
|
||||
IoUnregisterPlugPlayNotification(DeviceExtension->EchoCancelNotificationEntry);
|
||||
|
||||
IoDeleteSymbolicLink(&SymlinkName);
|
||||
IoDeleteDevice(DeviceObject);
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
DriverEntry(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PUNICODE_STRING RegistryPath)
|
||||
{
|
||||
DPRINT("System audio graph builder (sysaudio) started\n");
|
||||
|
||||
/* Let ks handle these */
|
||||
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CREATE);
|
||||
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CLOSE);
|
||||
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_WRITE);
|
||||
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_DEVICE_CONTROL);
|
||||
|
||||
/* Let ks handle these */
|
||||
DriverObject->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower;
|
||||
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp;
|
||||
|
||||
/* Use provided ks unload function */
|
||||
DriverObject->DriverUnload = KsNullDriverUnload;
|
||||
|
||||
/* Sysaudio needs to do work on pnp, so handle it */
|
||||
DriverObject->MajorFunction[IRP_MJ_PNP] = SysAudio_Pnp;
|
||||
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = SysAudio_Shutdown;
|
||||
|
||||
/* Call our initialization function */
|
||||
return SysAudio_InstallDevice(DriverObject);
|
||||
}
|
468
drivers/wdm/audio/sysaudio/pin.c
Normal file
468
drivers/wdm/audio/sysaudio/pin.c
Normal file
|
@ -0,0 +1,468 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel Streaming
|
||||
* FILE: drivers/wdm/audio/sysaudio/deviface.c
|
||||
* PURPOSE: System Audio graph builder
|
||||
* PROGRAMMER: Johannes Anderwald
|
||||
*/
|
||||
|
||||
#include "sysaudio.h"
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
Pin_fnDeviceIoControl(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp)
|
||||
{
|
||||
PDISPATCH_CONTEXT Context;
|
||||
NTSTATUS Status;
|
||||
ULONG BytesReturned;
|
||||
PFILE_OBJECT FileObject = NULL;
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
|
||||
DPRINT("Pin_fnDeviceIoControl called DeviceObject %p Irp %p\n", DeviceObject, Irp);
|
||||
|
||||
/* Get current stack location */
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
/* The dispatch context is stored in the FsContext member */
|
||||
Context = (PDISPATCH_CONTEXT)IoStack->FileObject->FsContext;
|
||||
|
||||
/* Sanity check */
|
||||
ASSERT(Context);
|
||||
|
||||
/* acquire real pin file object */
|
||||
Status = ObReferenceObjectByHandle(Context->Handle, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
Irp->IoStatus.Information = 0;
|
||||
Irp->IoStatus.Status = Status;
|
||||
/* Complete the irp */
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Re-dispatch the request to the real target pin */
|
||||
Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IoStack->Parameters.DeviceIoControl.IoControlCode,
|
||||
IoStack->Parameters.DeviceIoControl.Type3InputBuffer,
|
||||
IoStack->Parameters.DeviceIoControl.InputBufferLength,
|
||||
Irp->UserBuffer,
|
||||
IoStack->Parameters.DeviceIoControl.OutputBufferLength,
|
||||
&BytesReturned);
|
||||
/* release file object */
|
||||
ObDereferenceObject(FileObject);
|
||||
|
||||
/* Save status and information */
|
||||
Irp->IoStatus.Information = BytesReturned;
|
||||
Irp->IoStatus.Status = Status;
|
||||
/* Complete the irp */
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
/* Done */
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
Pin_fnWrite(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp)
|
||||
{
|
||||
PDISPATCH_CONTEXT Context;
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
PFILE_OBJECT FileObject;
|
||||
NTSTATUS Status;
|
||||
|
||||
/* Get current stack location */
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
/* The dispatch context is stored in the FsContext member */
|
||||
Context = (PDISPATCH_CONTEXT)IoStack->FileObject->FsContext;
|
||||
|
||||
/* Sanity check */
|
||||
ASSERT(Context);
|
||||
|
||||
if (Context->hMixerPin)
|
||||
{
|
||||
// FIXME
|
||||
// call kmixer to convert stream
|
||||
UNIMPLEMENTED
|
||||
}
|
||||
|
||||
/* acquire real pin file object */
|
||||
Status = ObReferenceObjectByHandle(Context->Handle, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("failed\n");
|
||||
Irp->IoStatus.Information = 0;
|
||||
Irp->IoStatus.Status = Status;
|
||||
/* Complete the irp */
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* skip current irp location */
|
||||
IoSkipCurrentIrpStackLocation(Irp);
|
||||
|
||||
/* get next stack location */
|
||||
IoStack = IoGetNextIrpStackLocation(Irp);
|
||||
/* store file object of next device object */
|
||||
IoStack->FileObject = FileObject;
|
||||
IoStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
|
||||
//ASSERT(Irp->AssociatedIrp.SystemBuffer);
|
||||
|
||||
/* now call the driver */
|
||||
Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
|
||||
|
||||
/* dereference file object */
|
||||
ObDereferenceObject(FileObject);
|
||||
|
||||
return Status;
|
||||
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
Pin_fnClose(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp)
|
||||
{
|
||||
PDISPATCH_CONTEXT Context;
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
|
||||
//DPRINT("Pin_fnClose called DeviceObject %p Irp %p\n", DeviceObject, Irp);
|
||||
|
||||
/* Get current stack location */
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
/* The dispatch context is stored in the FsContext member */
|
||||
Context = (PDISPATCH_CONTEXT)IoStack->FileObject->FsContext;
|
||||
|
||||
if (Context->Handle)
|
||||
{
|
||||
ZwClose(Context->Handle);
|
||||
}
|
||||
|
||||
if (Context->hMixerPin)
|
||||
{
|
||||
ZwClose(Context->hMixerPin);
|
||||
}
|
||||
|
||||
ExFreePool(Context);
|
||||
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
Irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static KSDISPATCH_TABLE PinTable =
|
||||
{
|
||||
Pin_fnDeviceIoControl,
|
||||
KsDispatchInvalidDeviceRequest,
|
||||
Pin_fnWrite,
|
||||
KsDispatchInvalidDeviceRequest,
|
||||
Pin_fnClose,
|
||||
KsDispatchInvalidDeviceRequest,
|
||||
KsDispatchInvalidDeviceRequest,
|
||||
KsDispatchFastIoDeviceControlFailure,
|
||||
KsDispatchFastReadFailure,
|
||||
KsDispatchFastWriteFailure,
|
||||
};
|
||||
|
||||
NTSTATUS
|
||||
SetMixerInputOutputFormat(
|
||||
IN PFILE_OBJECT FileObject,
|
||||
IN PKSDATAFORMAT InputFormat,
|
||||
IN PKSDATAFORMAT OutputFormat)
|
||||
{
|
||||
KSP_PIN PinRequest;
|
||||
ULONG BytesReturned;
|
||||
NTSTATUS Status;
|
||||
|
||||
/* re-using pin */
|
||||
PinRequest.Property.Set = KSPROPSETID_Connection;
|
||||
PinRequest.Property.Flags = KSPROPERTY_TYPE_SET;
|
||||
PinRequest.Property.Id = KSPROPERTY_CONNECTION_DATAFORMAT;
|
||||
|
||||
/* set the input format */
|
||||
PinRequest.PinId = 0;
|
||||
DPRINT("InputFormat %p Size %u WaveFormatSize %u DataFormat %u WaveEx %u\n", InputFormat, InputFormat->FormatSize, sizeof(KSDATAFORMAT_WAVEFORMATEX), sizeof(KSDATAFORMAT), sizeof(WAVEFORMATEX));
|
||||
Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY,
|
||||
(PVOID)&PinRequest,
|
||||
sizeof(KSP_PIN),
|
||||
(PVOID)InputFormat,
|
||||
InputFormat->FormatSize,
|
||||
&BytesReturned);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
/* set the the output format */
|
||||
PinRequest.PinId = 1;
|
||||
DPRINT("OutputFormat %p Size %u WaveFormatSize %u DataFormat %u WaveEx %u\n", OutputFormat, OutputFormat->FormatSize, sizeof(KSDATAFORMAT_WAVEFORMATEX), sizeof(KSDATAFORMAT), sizeof(WAVEFORMATEX));
|
||||
Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY,
|
||||
(PVOID)&PinRequest,
|
||||
sizeof(KSP_PIN),
|
||||
(PVOID)OutputFormat,
|
||||
OutputFormat->FormatSize,
|
||||
&BytesReturned);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CreateMixerPinAndSetFormat(
|
||||
IN HANDLE KMixerHandle,
|
||||
IN KSPIN_CONNECT *PinConnect,
|
||||
IN PKSDATAFORMAT InputFormat,
|
||||
IN PKSDATAFORMAT OutputFormat,
|
||||
OUT PHANDLE MixerPinHandle)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HANDLE PinHandle;
|
||||
PFILE_OBJECT FileObject = NULL;
|
||||
|
||||
Status = KsCreatePin(KMixerHandle, PinConnect, GENERIC_READ | GENERIC_WRITE, &PinHandle);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to create Mixer Pin with %x\n", Status);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
Status = ObReferenceObjectByHandle(PinHandle,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to get file object with %x\n", Status);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
Status = SetMixerInputOutputFormat(FileObject, InputFormat, OutputFormat);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ObDereferenceObject(FileObject);
|
||||
ZwClose(PinHandle);
|
||||
return Status;
|
||||
}
|
||||
|
||||
ObDereferenceObject(FileObject);
|
||||
|
||||
*MixerPinHandle = PinHandle;
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
InstantiatePins(
|
||||
IN PKSAUDIO_DEVICE_ENTRY DeviceEntry,
|
||||
IN PKSPIN_CONNECT Connect,
|
||||
IN PDISPATCH_CONTEXT DispatchContext,
|
||||
IN PSYSAUDIODEVEXT DeviceExtension)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HANDLE RealPinHandle;
|
||||
PKSDATAFORMAT_WAVEFORMATEX InputFormat;
|
||||
PKSDATAFORMAT_WAVEFORMATEX OutputFormat = NULL;
|
||||
PKSPIN_CONNECT MixerPinConnect = NULL;
|
||||
KSPIN_CINSTANCES PinInstances;
|
||||
|
||||
DPRINT("InstantiatePins entered\n");
|
||||
|
||||
/* query instance count */
|
||||
Status = GetPinInstanceCount(DeviceEntry, &PinInstances, Connect);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* failed to query instance count */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* can be the pin be instantiated */
|
||||
if (PinInstances.PossibleCount == 0)
|
||||
{
|
||||
/* caller wanted to open an instance-less pin */
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* has the maximum instance count been exceeded */
|
||||
if (PinInstances.CurrentCount == PinInstances.PossibleCount)
|
||||
{
|
||||
/* FIXME pin already exists
|
||||
* and kmixer infrastructure is not implemented
|
||||
*/
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* Fetch input format */
|
||||
InputFormat = (PKSDATAFORMAT_WAVEFORMATEX)(Connect + 1);
|
||||
|
||||
/* Let's try to create the audio irp pin */
|
||||
Status = KsCreatePin(DeviceEntry->Handle, Connect, GENERIC_READ | GENERIC_WRITE, &RealPinHandle);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* FIXME disable kmixer
|
||||
*/
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
#if 0
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* the audio irp pin didnt accept the input format
|
||||
* let's compute a compatible format
|
||||
*/
|
||||
MixerPinConnect = ExAllocatePool(NonPagedPool, sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX));
|
||||
if (!MixerPinConnect)
|
||||
{
|
||||
/* not enough memory */
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* Zero pin connect */
|
||||
RtlZeroMemory(MixerPinConnect, sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX));
|
||||
|
||||
/* Copy initial connect details */
|
||||
RtlMoveMemory(MixerPinConnect, Connect, sizeof(KSPIN_CONNECT));
|
||||
|
||||
|
||||
OutputFormat = (PKSDATAFORMAT_WAVEFORMATEX)(MixerPinConnect + 1);
|
||||
|
||||
Status = ComputeCompatibleFormat(DeviceEntry, Connect->PinId, InputFormat, OutputFormat);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("ComputeCompatibleFormat failed with %x\n", Status);
|
||||
ExFreePool(MixerPinConnect);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Retry with Mixer format */
|
||||
Status = KsCreatePin(DeviceEntry->Handle, MixerPinConnect, GENERIC_READ | GENERIC_WRITE, &RealPinHandle);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* This should not fail */
|
||||
DPRINT1("KsCreatePin failed with %x\n", Status);
|
||||
DPRINT1(" InputFormat: SampleRate %u Bits %u Channels %u\n", InputFormat->WaveFormatEx.nSamplesPerSec, InputFormat->WaveFormatEx.wBitsPerSample, InputFormat->WaveFormatEx.nChannels);
|
||||
DPRINT1("OutputFormat: SampleRate %u Bits %u Channels %u\n", OutputFormat->WaveFormatEx.nSamplesPerSec, OutputFormat->WaveFormatEx.wBitsPerSample, OutputFormat->WaveFormatEx.nChannels);
|
||||
|
||||
ExFreePool(MixerPinConnect);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DeviceEntry->Pins[Connect->PinId].References = 0;
|
||||
|
||||
/* initialize dispatch context */
|
||||
DispatchContext->Handle = RealPinHandle;
|
||||
DispatchContext->PinId = Connect->PinId;
|
||||
DispatchContext->AudioEntry = DeviceEntry;
|
||||
|
||||
|
||||
DPRINT("RealPinHandle %p\n", RealPinHandle);
|
||||
|
||||
/* Do we need to transform the audio stream */
|
||||
if (OutputFormat != NULL)
|
||||
{
|
||||
/* Now create the mixer pin */
|
||||
Status = CreateMixerPinAndSetFormat(DeviceExtension->KMixerHandle,
|
||||
MixerPinConnect,
|
||||
(PKSDATAFORMAT)InputFormat,
|
||||
(PKSDATAFORMAT)OutputFormat,
|
||||
&DispatchContext->hMixerPin);
|
||||
|
||||
/* check for success */
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to create Mixer Pin with %x\n", Status);
|
||||
ExFreePool(MixerPinConnect);
|
||||
}
|
||||
}
|
||||
/* done */
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
DispatchCreateSysAudioPin(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
PKSAUDIO_DEVICE_ENTRY DeviceEntry;
|
||||
PKSPIN_CONNECT Connect = NULL;
|
||||
PDISPATCH_CONTEXT DispatchContext;
|
||||
|
||||
DPRINT("DispatchCreateSysAudioPin entered\n");
|
||||
|
||||
/* get current stack location */
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
/* sanity checks */
|
||||
ASSERT(IoStack->FileObject);
|
||||
ASSERT(IoStack->FileObject->RelatedFileObject);
|
||||
ASSERT(IoStack->FileObject->RelatedFileObject->FsContext);
|
||||
|
||||
/* get current attached virtual device */
|
||||
DeviceEntry = (PKSAUDIO_DEVICE_ENTRY)IoStack->FileObject->RelatedFileObject->FsContext;
|
||||
|
||||
/* now validate pin connect request */
|
||||
Status = KsValidateConnectRequest(Irp, DeviceEntry->PinDescriptorsCount, DeviceEntry->PinDescriptors, &Connect);
|
||||
|
||||
/* check for success */
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* failed */
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* allocate dispatch context */
|
||||
DispatchContext = ExAllocatePool(NonPagedPool, sizeof(DISPATCH_CONTEXT));
|
||||
if (!DispatchContext)
|
||||
{
|
||||
/* failed */
|
||||
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* zero dispatch context */
|
||||
RtlZeroMemory(DispatchContext, sizeof(DISPATCH_CONTEXT));
|
||||
|
||||
/* allocate object header */
|
||||
Status = KsAllocateObjectHeader(&DispatchContext->ObjectHeader, 0, NULL, Irp, &PinTable);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* failed */
|
||||
ExFreePool(DispatchContext);
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* now instantiate the pins */
|
||||
Status = InstantiatePins(DeviceEntry, Connect, DispatchContext, (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* failed */
|
||||
KsFreeObjectHeader(DispatchContext->ObjectHeader);
|
||||
ExFreePool(DispatchContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* store dispatch context */
|
||||
IoStack->FileObject->FsContext = (PVOID)DispatchContext;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME create items for clocks / allocators */
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Status;
|
||||
}
|
134
drivers/wdm/audio/sysaudio/sysaudio.h
Normal file
134
drivers/wdm/audio/sysaudio/sysaudio.h
Normal file
|
@ -0,0 +1,134 @@
|
|||
#pragma once
|
||||
|
||||
#include <ntifs.h>
|
||||
#include <ntddk.h>
|
||||
#include <portcls.h>
|
||||
#include <ks.h>
|
||||
#include <ksmedia.h>
|
||||
#include <math.h>
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE PinHandle; // handle to audio irp pin
|
||||
ULONG References; // number of clients having a reference to this audio irp pin
|
||||
}PIN_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LIST_ENTRY Entry; // device entry for KsAudioDeviceList
|
||||
UNICODE_STRING DeviceName; // symbolic link of audio device
|
||||
|
||||
HANDLE Handle; // handle to audio device
|
||||
PFILE_OBJECT FileObject; // file objecto to audio device
|
||||
|
||||
PIN_INFO * Pins; // array of PIN_INFO
|
||||
ULONG PinDescriptorsCount; // number of pin descriptors
|
||||
KSPIN_DESCRIPTOR *PinDescriptors; // pin descriptors array
|
||||
}KSAUDIO_DEVICE_ENTRY, *PKSAUDIO_DEVICE_ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
KSDEVICE_HEADER KsDeviceHeader; // ks streaming header - must always be first item in device extension
|
||||
PDEVICE_OBJECT PhysicalDeviceObject; // pdo
|
||||
PDEVICE_OBJECT NextDeviceObject; // lower device object
|
||||
ULONG NumberOfKsAudioDevices; // number of audio devices
|
||||
|
||||
LIST_ENTRY KsAudioDeviceList; // audio device list
|
||||
PVOID KsAudioNotificationEntry; // ks audio notification hook
|
||||
PVOID EchoCancelNotificationEntry; // ks echo cancel notification hook
|
||||
KSPIN_LOCK Lock; // audio device list mutex
|
||||
|
||||
PFILE_OBJECT KMixerFileObject; // mixer file object
|
||||
HANDLE KMixerHandle; // mixer file handle
|
||||
|
||||
}SYSAUDIODEVEXT, *PSYSAUDIODEVEXT;
|
||||
|
||||
// struct DISPATCH_CONTEXT
|
||||
//
|
||||
// This structure is used to dispatch read / write / device io requests
|
||||
// It is stored in the file object FsContext2 member
|
||||
// Note: FsContext member is reserved for ks object header
|
||||
|
||||
typedef struct
|
||||
{
|
||||
KSOBJECT_HEADER ObjectHeader; // pin object header
|
||||
HANDLE Handle; // audio irp pin handle
|
||||
ULONG PinId; // pin id of device
|
||||
PKSAUDIO_DEVICE_ENTRY AudioEntry; // pointer to audio device entry
|
||||
|
||||
HANDLE hMixerPin; // handle to mixer pin
|
||||
}DISPATCH_CONTEXT, *PDISPATCH_CONTEXT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PIO_WORKITEM WorkItem;
|
||||
PKSAUDIO_DEVICE_ENTRY DeviceEntry;
|
||||
}FILTER_WORKER_CONTEXT, *PFILTER_WORKER_CONTEXT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PIRP Irp;
|
||||
IO_STATUS_BLOCK StatusBlock;
|
||||
}COMPLETION_CONTEXT, *PCOMPLETION_CONTEXT;
|
||||
|
||||
|
||||
|
||||
NTSTATUS
|
||||
SysAudioAllocateDeviceHeader(
|
||||
IN SYSAUDIODEVEXT *DeviceExtension);
|
||||
|
||||
NTSTATUS
|
||||
SysAudioRegisterDeviceInterfaces(
|
||||
IN PDEVICE_OBJECT DeviceObject);
|
||||
|
||||
NTSTATUS
|
||||
SysAudioRegisterNotifications(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PDEVICE_OBJECT DeviceObject);
|
||||
|
||||
NTSTATUS
|
||||
SysAudioHandleProperty(
|
||||
PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp);
|
||||
|
||||
NTSTATUS
|
||||
SysAudioOpenKMixer(
|
||||
IN SYSAUDIODEVEXT *DeviceExtension);
|
||||
|
||||
NTSTATUS
|
||||
OpenDevice(
|
||||
IN PUNICODE_STRING DeviceName,
|
||||
IN PHANDLE HandleOut,
|
||||
IN PFILE_OBJECT * FileObjectOut);
|
||||
|
||||
PKSAUDIO_DEVICE_ENTRY
|
||||
GetListEntry(
|
||||
IN PLIST_ENTRY Head,
|
||||
IN ULONG Index);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
DispatchCreateSysAudioPin(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
ULONG
|
||||
GetDeviceCount(
|
||||
PSYSAUDIODEVEXT DeviceExtension,
|
||||
BOOL WaveIn);
|
||||
|
||||
NTSTATUS
|
||||
GetPinInstanceCount(
|
||||
PKSAUDIO_DEVICE_ENTRY Entry,
|
||||
PKSPIN_CINSTANCES PinInstances,
|
||||
PKSPIN_CONNECT PinConnect);
|
||||
|
||||
NTSTATUS
|
||||
ComputeCompatibleFormat(
|
||||
IN PKSAUDIO_DEVICE_ENTRY Entry,
|
||||
IN ULONG PinId,
|
||||
IN PKSDATAFORMAT_WAVEFORMATEX ClientFormat,
|
||||
OUT PKSDATAFORMAT_WAVEFORMATEX MixerFormat);
|
16
drivers/wdm/audio/sysaudio/sysaudio.rbuild
Normal file
16
drivers/wdm/audio/sysaudio/sysaudio.rbuild
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
|
||||
<module name="sysaudio" type="kernelmodedriver" installbase="system32/drivers" installname="sysaudio.sys">
|
||||
<include base="sysaudio">.</include>
|
||||
<library>ntoskrnl</library>
|
||||
<library>ks</library>
|
||||
<library>hal</library>
|
||||
<library>libcntpr</library>
|
||||
<define name="_COMDDK_" />
|
||||
<file>control.c</file>
|
||||
<file>deviface.c</file>
|
||||
<file>dispatcher.c</file>
|
||||
<file>main.c</file>
|
||||
<file>pin.c</file>
|
||||
<file>sysaudio.rc</file>
|
||||
</module>
|
5
drivers/wdm/audio/sysaudio/sysaudio.rc
Normal file
5
drivers/wdm/audio/sysaudio/sysaudio.rc
Normal file
|
@ -0,0 +1,5 @@
|
|||
#define REACTOS_VERSION_DLL
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "System Audio Graph Builder\0"
|
||||
#define REACTOS_STR_INTERNAL_NAME "sysaudio\0"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "sysaudio.sys\0"
|
||||
#include <reactos/version.rc>
|
Loading…
Add table
Add a link
Reference in a new issue