2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/sysaudio/deviface.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Johannes Anderwald
11 const GUID GUID_DEVICE_INTERFACE_ARRIVAL
= {0xCB3A4004L
, 0x46F0, 0x11D0, {0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F}};
12 const GUID GUID_DEVICE_INTERFACE_REMOVAL
= {0xCB3A4005L
, 0x46F0, 0x11D0, {0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F}};
13 const GUID KS_CATEGORY_AUDIO
= {0x6994AD04L
, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
14 const GUID KS_CATEGORY_TOPOLOGY
= {0xDDA54A40, 0x1E4C, 0x11D1, {0xA0, 0x50, 0x40, 0x57, 0x05, 0xC1, 0x00, 0x00}};
15 const GUID DMOCATEGORY_ACOUSTIC_ECHO_CANCEL
= {0xBF963D80L
, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
17 #define IOCTL_KS_OBJECT_CLASS CTL_CODE(FILE_DEVICE_KS, 0x7, METHOD_NEITHER, FILE_ANY_ACCESS)
21 IN PKSAUDIO_DEVICE_ENTRY DeviceEntry
,
26 KSPIN_DATAFLOW DataFlow
;
27 KSPIN_COMMUNICATION Communication
;
28 ULONG NumWaveOutPin
, NumWaveInPin
;
34 for(Index
= 0; Index
< Count
; Index
++)
36 /* retrieve data flow */
37 PinRequest
.PinId
= Index
;
38 PinRequest
.Property
.Set
= KSPROPSETID_Pin
;
39 PinRequest
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
41 /* get dataflow direction */
42 PinRequest
.Property
.Id
= KSPROPERTY_PIN_DATAFLOW
;
43 Status
= KsSynchronousIoControlDevice(DeviceEntry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&PinRequest
, sizeof(KSP_PIN
), (PVOID
)&DataFlow
, sizeof(KSPIN_DATAFLOW
), &BytesReturned
);
44 if (NT_SUCCESS(Status
))
46 DeviceEntry
->PinDescriptors
[Index
].DataFlow
= DataFlow
;
49 /* get irp flow direction */
50 PinRequest
.Property
.Id
= KSPROPERTY_PIN_COMMUNICATION
;
51 Status
= KsSynchronousIoControlDevice(DeviceEntry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&PinRequest
, sizeof(KSP_PIN
), (PVOID
)&Communication
, sizeof(KSPIN_COMMUNICATION
), &BytesReturned
);
52 if (NT_SUCCESS(Status
))
54 DeviceEntry
->PinDescriptors
[Index
].Communication
= Communication
;
57 if (Communication
== KSPIN_COMMUNICATION_SINK
&& DataFlow
== KSPIN_DATAFLOW_IN
)
60 if (Communication
== KSPIN_COMMUNICATION_SINK
&& DataFlow
== KSPIN_DATAFLOW_OUT
)
63 /* FIXME query for interface, dataformat etc */
66 DPRINT("Num Pins %u Num WaveIn Pins %u Name WaveOut Pins %u\n", DeviceEntry
->PinDescriptorsCount
, NumWaveInPin
, NumWaveOutPin
);
67 return STATUS_SUCCESS
;
72 IN PKSAUDIO_DEVICE_ENTRY DeviceEntry
)
74 KSPROPERTY PropertyRequest
;
79 DPRINT("Querying filter...\n");
81 PropertyRequest
.Set
= KSPROPSETID_Pin
;
82 PropertyRequest
.Flags
= KSPROPERTY_TYPE_GET
;
83 PropertyRequest
.Id
= KSPROPERTY_PIN_CTYPES
;
85 /* query for num of pins */
86 Status
= KsSynchronousIoControlDevice(DeviceEntry
->FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&PropertyRequest
, sizeof(KSPROPERTY
), (PVOID
)&Count
, sizeof(ULONG
), &BytesReturned
);
87 if (!NT_SUCCESS(Status
))
89 DPRINT1("Failed to query number of pins Status %x\n", Status
);
95 DPRINT1("Filter has no pins!\n");
99 /* allocate pin descriptor array */
100 DeviceEntry
->PinDescriptors
= ExAllocatePool(NonPagedPool
, Count
* sizeof(KSPIN_DESCRIPTOR
));
101 if (!DeviceEntry
->PinDescriptors
)
107 /* zero array pin descriptor array */
108 RtlZeroMemory(DeviceEntry
->PinDescriptors
, Count
* sizeof(KSPIN_DESCRIPTOR
));
110 /* build the device descriptor */
111 Status
= BuildPinDescriptor(DeviceEntry
, Count
);
112 if (!NT_SUCCESS(Status
))
116 /* allocate pin array */
117 DeviceEntry
->Pins
= ExAllocatePool(NonPagedPool
, Count
* sizeof(PIN_INFO
));
118 if (!DeviceEntry
->Pins
)
121 DPRINT1("Failed to allocate memory Pins %u Block %x\n", Count
, Count
* sizeof(PIN_INFO
));
126 RtlZeroMemory(DeviceEntry
->Pins
, sizeof(PIN_INFO
) * Count
);
127 DeviceEntry
->PinDescriptorsCount
= Count
;
133 FilterPinWorkerRoutine(
134 IN PDEVICE_OBJECT DeviceObject
,
137 PKSAUDIO_DEVICE_ENTRY DeviceEntry
;
138 PFILTER_WORKER_CONTEXT Ctx
= (PFILTER_WORKER_CONTEXT
)Context
;
140 DeviceEntry
= Ctx
->DeviceEntry
;
142 QueryFilterRoutine(DeviceEntry
);
145 IoFreeWorkItem(Ctx
->WorkItem
);
146 /* free work item context */
154 IN PUNICODE_STRING DeviceName
,
155 IN PHANDLE HandleOut
,
156 IN PFILE_OBJECT
* FileObjectOut
)
160 PFILE_OBJECT FileObject
;
161 OBJECT_ATTRIBUTES ObjectAttributes
;
162 IO_STATUS_BLOCK IoStatusBlock
;
164 InitializeObjectAttributes(&ObjectAttributes
, DeviceName
, OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
166 Status
= ZwCreateFile(&NodeHandle
,
167 GENERIC_READ
| GENERIC_WRITE
,
174 FILE_SYNCHRONOUS_IO_NONALERT
,
179 if (!NT_SUCCESS(Status
))
181 DPRINT("ZwCreateFile failed with %x %S\n", Status
, DeviceName
->Buffer
);
185 Status
= ObReferenceObjectByHandle(NodeHandle
, GENERIC_READ
| GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
186 if (!NT_SUCCESS(Status
))
189 DPRINT("ObReferenceObjectByHandle failed with %x\n", Status
);
193 *HandleOut
= NodeHandle
;
194 *FileObjectOut
= FileObject
;
200 IN PDEVICE_OBJECT DeviceObject
,
201 IN PUNICODE_STRING DeviceName
,
202 IN LPWSTR ReferenceString
)
204 NTSTATUS Status
= STATUS_SUCCESS
;
205 PFILTER_WORKER_CONTEXT Ctx
= NULL
;
206 PIO_WORKITEM WorkItem
= NULL
;
207 PSYSAUDIODEVEXT DeviceExtension
;
208 PKSAUDIO_DEVICE_ENTRY DeviceEntry
= NULL
;
210 /* a new device has arrived */
211 DeviceEntry
= ExAllocatePool(NonPagedPool
, sizeof(KSAUDIO_DEVICE_ENTRY
));
215 return STATUS_INSUFFICIENT_RESOURCES
;
218 /* initialize audio device entry */
219 RtlZeroMemory(DeviceEntry
, sizeof(KSAUDIO_DEVICE_ENTRY
));
221 /* allocate filter ctx */
222 Ctx
= ExAllocatePool(NonPagedPool
, sizeof(FILTER_WORKER_CONTEXT
));
226 Status
= STATUS_INSUFFICIENT_RESOURCES
;
230 /* allocate work item */
231 WorkItem
= IoAllocateWorkItem(DeviceObject
);
235 Status
= STATUS_INSUFFICIENT_RESOURCES
;
239 /* set device name */
240 DeviceEntry
->DeviceName
.Length
= 0;
241 DeviceEntry
->DeviceName
.MaximumLength
= DeviceName
->MaximumLength
+ 10 * sizeof(WCHAR
);
243 /* hack for bug 4566 */
246 DeviceEntry
->DeviceName
.MaximumLength
+= (wcslen(ReferenceString
) + 2) * sizeof(WCHAR
);
249 DeviceEntry
->DeviceName
.Buffer
= ExAllocatePool(NonPagedPool
, DeviceEntry
->DeviceName
.MaximumLength
);
251 if (!DeviceEntry
->DeviceName
.Buffer
)
253 Status
= STATUS_INSUFFICIENT_RESOURCES
;
257 RtlAppendUnicodeToString(&DeviceEntry
->DeviceName
, L
"\\??\\");
258 RtlAppendUnicodeStringToString(&DeviceEntry
->DeviceName
, DeviceName
);
262 RtlAppendUnicodeToString(&DeviceEntry
->DeviceName
, L
"\\");
263 RtlAppendUnicodeToString(&DeviceEntry
->DeviceName
, ReferenceString
);
266 Status
= OpenDevice(&DeviceEntry
->DeviceName
, &DeviceEntry
->Handle
, &DeviceEntry
->FileObject
);
268 if (!NT_SUCCESS(Status
))
273 Ctx
->DeviceEntry
= DeviceEntry
;
274 Ctx
->WorkItem
= WorkItem
;
276 /* fetch device extension */
277 DeviceExtension
= (PSYSAUDIODEVEXT
)DeviceObject
->DeviceExtension
;
278 /* insert new audio device */
279 ExInterlockedInsertTailList(&DeviceExtension
->KsAudioDeviceList
, &DeviceEntry
->Entry
, &DeviceExtension
->Lock
);
280 InterlockedIncrement((PLONG
)&DeviceExtension
->NumberOfKsAudioDevices
);
282 DPRINT("Successfully opened audio device %u Device %S\n", DeviceExtension
->NumberOfKsAudioDevices
, DeviceEntry
->DeviceName
.Buffer
);
283 IoQueueWorkItem(WorkItem
, FilterPinWorkerRoutine
, DelayedWorkQueue
, (PVOID
)Ctx
);
291 IoFreeWorkItem(WorkItem
);
295 if (DeviceEntry
->DeviceName
.Buffer
)
296 ExFreePool(DeviceEntry
->DeviceName
.Buffer
);
298 ExFreePool(DeviceEntry
);
308 DeviceInterfaceChangeCallback(
309 IN PVOID NotificationStructure
,
312 DEVICE_INTERFACE_CHANGE_NOTIFICATION
* Event
;
313 NTSTATUS Status
= STATUS_SUCCESS
;
314 PSYSAUDIODEVEXT DeviceExtension
;
315 UNICODE_STRING DeviceName
;
317 PFILE_OBJECT FileObject
;
318 LPWSTR ReferenceString
;
322 PDEVICE_OBJECT DeviceObject
= (PDEVICE_OBJECT
)Context
;
324 DeviceExtension
= (PSYSAUDIODEVEXT
)DeviceObject
->DeviceExtension
;
326 Event
= (DEVICE_INTERFACE_CHANGE_NOTIFICATION
*)NotificationStructure
;
328 if (IsEqualGUIDAligned(&Event
->Event
,
329 &GUID_DEVICE_INTERFACE_ARRIVAL
))
332 * 1) Open the filter w/o reference string
333 * 2) Retrieve reference strings with our private IOCTL_KS_OBJECT_CLASS
334 * 3) Append these reference strings to symbolic link we got
338 DeviceName
.Length
= 0;
339 DeviceName
.MaximumLength
= Event
->SymbolicLinkName
->Length
+ 10 * sizeof(WCHAR
);
341 DeviceName
.Buffer
= ExAllocatePool(NonPagedPool
, DeviceName
.MaximumLength
);
343 if (!DeviceName
.Buffer
)
345 return STATUS_INSUFFICIENT_RESOURCES
;
348 RtlAppendUnicodeToString(&DeviceName
, L
"\\??\\");
349 RtlAppendUnicodeStringToString(&DeviceName
, Event
->SymbolicLinkName
);
352 Status
= OpenDevice(&DeviceName
, &Handle
, &FileObject
);
353 if (!NT_SUCCESS(Status
))
355 ExFreePool(DeviceName
.Buffer
);
359 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_OBJECT_CLASS
, NULL
, 0, &ReferenceString
, sizeof(LPWSTR
), &BytesReturned
);
360 if (!NT_SUCCESS(Status
))
362 DPRINT1("failed Status %x\n", Status
);
364 ExFreePool(DeviceName
.Buffer
);
365 ObDereferenceObject(FileObject
);
370 while(*ReferenceString
)
372 Status
= InsertAudioDevice(DeviceObject
, Event
->SymbolicLinkName
, ReferenceString
);
373 ReferenceString
+= wcslen(ReferenceString
) + 1;
375 //ExFreePool(ReferenceString);
376 ObDereferenceObject(FileObject
);
378 ExFreePool(DeviceName
.Buffer
);
383 DPRINT("Remove interface to audio device!\n");
385 return STATUS_SUCCESS
;
392 SysAudioRegisterNotifications(
393 IN PDRIVER_OBJECT DriverObject
,
394 IN PDEVICE_OBJECT DeviceObject
)
397 PSYSAUDIODEVEXT DeviceExtension
;
399 DeviceExtension
= (PSYSAUDIODEVEXT
)DeviceObject
->DeviceExtension
;
401 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
402 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
403 (PVOID
)&KS_CATEGORY_AUDIO
,
405 DeviceInterfaceChangeCallback
,
407 (PVOID
*)&DeviceExtension
->KsAudioNotificationEntry
);
409 if (!NT_SUCCESS(Status
))
411 DPRINT("IoRegisterPlugPlayNotification failed with %x\n", Status
);
414 Status
= IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange
,
415 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES
,
416 (PVOID
)&DMOCATEGORY_ACOUSTIC_ECHO_CANCEL
,
418 DeviceInterfaceChangeCallback
,
420 (PVOID
*)&DeviceExtension
->EchoCancelNotificationEntry
);
422 if (!NT_SUCCESS(Status
))
424 /* ignore failure for now */
425 DPRINT("IoRegisterPlugPlayNotification failed for DMOCATEGORY_ACOUSTIC_ECHO_CANCEL\n", Status
);
428 return STATUS_SUCCESS
;
434 SysAudioRegisterDeviceInterfaces(
435 IN PDEVICE_OBJECT DeviceObject
)
438 UNICODE_STRING SymbolicLink
;
440 Status
= IoRegisterDeviceInterface(DeviceObject
, &KSCATEGORY_PREFERRED_MIDIOUT_DEVICE
, NULL
, &SymbolicLink
);
441 if (NT_SUCCESS(Status
))
443 IoSetDeviceInterfaceState(&SymbolicLink
, TRUE
);
444 RtlFreeUnicodeString(&SymbolicLink
);
448 DPRINT("Failed to register KSCATEGORY_PREFERRED_MIDIOUT_DEVICE interface Status %x\n", Status
);
452 Status
= IoRegisterDeviceInterface(DeviceObject
, &KSCATEGORY_PREFERRED_WAVEIN_DEVICE
, NULL
, &SymbolicLink
);
453 if (NT_SUCCESS(Status
))
455 IoSetDeviceInterfaceState(&SymbolicLink
, TRUE
);
456 RtlFreeUnicodeString(&SymbolicLink
);
460 DPRINT("Failed to register KSCATEGORY_PREFERRED_WAVEIN_DEVICE interface Status %x\n", Status
);
464 Status
= IoRegisterDeviceInterface(DeviceObject
, &KSCATEGORY_PREFERRED_WAVEOUT_DEVICE
, NULL
, &SymbolicLink
);
465 if (NT_SUCCESS(Status
))
467 IoSetDeviceInterfaceState(&SymbolicLink
, TRUE
);
468 RtlFreeUnicodeString(&SymbolicLink
);
472 DPRINT("Failed to register KSCATEGORY_PREFERRED_WAVEOUT_DEVICE interface Status %x\n", Status
);
475 Status
= IoRegisterDeviceInterface(DeviceObject
, &KSCATEGORY_SYSAUDIO
, NULL
, &SymbolicLink
);
476 if (NT_SUCCESS(Status
))
478 IoSetDeviceInterfaceState(&SymbolicLink
, TRUE
);
479 RtlFreeUnicodeString(&SymbolicLink
);
483 DPRINT("Failed to register KSCATEGORY_SYSAUDIO interface Status %x\n", Status
);