xref: /reactos/drivers/wdm/audio/sysaudio/deviface.c (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * COPYRIGHT:       See COPYING in the top level directory
3*c2c66affSColin Finck  * PROJECT:         ReactOS Kernel Streaming
4*c2c66affSColin Finck  * FILE:            drivers/wdm/audio/sysaudio/deviface.c
5*c2c66affSColin Finck  * PURPOSE:         System Audio graph builder
6*c2c66affSColin Finck  * PROGRAMMER:      Johannes Anderwald
7*c2c66affSColin Finck  */
8*c2c66affSColin Finck 
9*c2c66affSColin Finck #include "sysaudio.h"
10*c2c66affSColin Finck 
11*c2c66affSColin Finck #define NDEBUG
12*c2c66affSColin Finck #include <debug.h>
13*c2c66affSColin Finck 
14*c2c66affSColin Finck const GUID GUID_DEVICE_INTERFACE_ARRIVAL       = {0xCB3A4004L, 0x46F0, 0x11D0, {0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F}};
15*c2c66affSColin Finck const GUID GUID_DEVICE_INTERFACE_REMOVAL       = {0xCB3A4005L, 0x46F0, 0x11D0, {0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F}};
16*c2c66affSColin Finck const GUID KS_CATEGORY_AUDIO                   = {0x6994AD04L, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
17*c2c66affSColin Finck const GUID KS_CATEGORY_TOPOLOGY                = {0xDDA54A40, 0x1E4C, 0x11D1, {0xA0, 0x50, 0x40, 0x57, 0x05, 0xC1, 0x00, 0x00}};
18*c2c66affSColin Finck const GUID DMOCATEGORY_ACOUSTIC_ECHO_CANCEL    = {0xBF963D80L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
19*c2c66affSColin Finck 
20*c2c66affSColin Finck NTSTATUS
OpenDevice(IN PUNICODE_STRING DeviceName,IN PHANDLE HandleOut,IN PFILE_OBJECT * FileObjectOut)21*c2c66affSColin Finck OpenDevice(
22*c2c66affSColin Finck     IN PUNICODE_STRING DeviceName,
23*c2c66affSColin Finck     IN PHANDLE HandleOut,
24*c2c66affSColin Finck     IN PFILE_OBJECT * FileObjectOut)
25*c2c66affSColin Finck {
26*c2c66affSColin Finck     NTSTATUS Status;
27*c2c66affSColin Finck     HANDLE NodeHandle;
28*c2c66affSColin Finck     PFILE_OBJECT FileObject;
29*c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
30*c2c66affSColin Finck     IO_STATUS_BLOCK IoStatusBlock;
31*c2c66affSColin Finck 
32*c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes, DeviceName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
33*c2c66affSColin Finck 
34*c2c66affSColin Finck     Status = ZwCreateFile(&NodeHandle,
35*c2c66affSColin Finck                           GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
36*c2c66affSColin Finck                           &ObjectAttributes,
37*c2c66affSColin Finck                           &IoStatusBlock,
38*c2c66affSColin Finck                           NULL,
39*c2c66affSColin Finck                           0,
40*c2c66affSColin Finck                           0,
41*c2c66affSColin Finck                           FILE_OPEN,
42*c2c66affSColin Finck                           FILE_SYNCHRONOUS_IO_NONALERT,
43*c2c66affSColin Finck                           NULL,
44*c2c66affSColin Finck                           0);
45*c2c66affSColin Finck 
46*c2c66affSColin Finck 
47*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
48*c2c66affSColin Finck     {
49*c2c66affSColin Finck         DPRINT("ZwCreateFile failed with %x %S\n", Status, DeviceName->Buffer);
50*c2c66affSColin Finck         return Status;
51*c2c66affSColin Finck     }
52*c2c66affSColin Finck 
53*c2c66affSColin Finck     Status = ObReferenceObjectByHandle(NodeHandle, GENERIC_READ | GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
54*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
55*c2c66affSColin Finck     {
56*c2c66affSColin Finck         ZwClose(NodeHandle);
57*c2c66affSColin Finck         DPRINT("ObReferenceObjectByHandle failed with %x\n", Status);
58*c2c66affSColin Finck         return Status;
59*c2c66affSColin Finck     }
60*c2c66affSColin Finck 
61*c2c66affSColin Finck     *HandleOut = NodeHandle;
62*c2c66affSColin Finck     *FileObjectOut = FileObject;
63*c2c66affSColin Finck     return Status;
64*c2c66affSColin Finck }
65*c2c66affSColin Finck 
66*c2c66affSColin Finck NTSTATUS
InsertAudioDevice(IN PDEVICE_OBJECT DeviceObject,IN PUNICODE_STRING DeviceName)67*c2c66affSColin Finck InsertAudioDevice(
68*c2c66affSColin Finck     IN PDEVICE_OBJECT DeviceObject,
69*c2c66affSColin Finck     IN PUNICODE_STRING DeviceName)
70*c2c66affSColin Finck {
71*c2c66affSColin Finck     NTSTATUS Status = STATUS_SUCCESS;
72*c2c66affSColin Finck     PSYSAUDIODEVEXT DeviceExtension;
73*c2c66affSColin Finck     PKSAUDIO_DEVICE_ENTRY DeviceEntry = NULL;
74*c2c66affSColin Finck 
75*c2c66affSColin Finck     /* a new device has arrived */
76*c2c66affSColin Finck     DeviceEntry = AllocateItem(NonPagedPool, sizeof(KSAUDIO_DEVICE_ENTRY));
77*c2c66affSColin Finck     if (!DeviceEntry)
78*c2c66affSColin Finck     {
79*c2c66affSColin Finck         /* no memory */
80*c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
81*c2c66affSColin Finck     }
82*c2c66affSColin Finck 
83*c2c66affSColin Finck     /* initialize audio device entry */
84*c2c66affSColin Finck     RtlZeroMemory(DeviceEntry, sizeof(KSAUDIO_DEVICE_ENTRY));
85*c2c66affSColin Finck 
86*c2c66affSColin Finck     /* set device name */
87*c2c66affSColin Finck     DeviceEntry->DeviceName.Length = 0;
88*c2c66affSColin Finck     DeviceEntry->DeviceName.MaximumLength = DeviceName->MaximumLength + 10 * sizeof(WCHAR);
89*c2c66affSColin Finck 
90*c2c66affSColin Finck     DeviceEntry->DeviceName.Buffer = AllocateItem(NonPagedPool, DeviceEntry->DeviceName.MaximumLength);
91*c2c66affSColin Finck 
92*c2c66affSColin Finck     if (!DeviceEntry->DeviceName.Buffer)
93*c2c66affSColin Finck     {
94*c2c66affSColin Finck         Status = STATUS_INSUFFICIENT_RESOURCES;
95*c2c66affSColin Finck         goto cleanup;
96*c2c66affSColin Finck     }
97*c2c66affSColin Finck 
98*c2c66affSColin Finck     /* open device */
99*c2c66affSColin Finck     Status = OpenDevice(DeviceName, &DeviceEntry->Handle, &DeviceEntry->FileObject);
100*c2c66affSColin Finck     if (NT_SUCCESS(Status))
101*c2c66affSColin Finck     {
102*c2c66affSColin Finck         /* copy device name */
103*c2c66affSColin Finck         RtlAppendUnicodeStringToString(&DeviceEntry->DeviceName, DeviceName);
104*c2c66affSColin Finck     }
105*c2c66affSColin Finck     else
106*c2c66affSColin Finck     {
107*c2c66affSColin Finck         /* the device name needs to be prefixed */
108*c2c66affSColin Finck         RtlAppendUnicodeToString(&DeviceEntry->DeviceName, L"\\??\\");
109*c2c66affSColin Finck         RtlAppendUnicodeStringToString(&DeviceEntry->DeviceName, DeviceName);
110*c2c66affSColin Finck 
111*c2c66affSColin Finck         /* open device */
112*c2c66affSColin Finck         Status = OpenDevice(&DeviceEntry->DeviceName, &DeviceEntry->Handle, &DeviceEntry->FileObject);
113*c2c66affSColin Finck     }
114*c2c66affSColin Finck 
115*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
116*c2c66affSColin Finck     {
117*c2c66affSColin Finck         goto cleanup;
118*c2c66affSColin Finck     }
119*c2c66affSColin Finck 
120*c2c66affSColin Finck     /* fetch device extension */
121*c2c66affSColin Finck     DeviceExtension = (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension;
122*c2c66affSColin Finck     /* insert new audio device */
123*c2c66affSColin Finck     ExInterlockedInsertTailList(&DeviceExtension->KsAudioDeviceList, &DeviceEntry->Entry, &DeviceExtension->Lock);
124*c2c66affSColin Finck     InterlockedIncrement((PLONG)&DeviceExtension->NumberOfKsAudioDevices);
125*c2c66affSColin Finck 
126*c2c66affSColin Finck     DPRINT("Successfully opened audio device %u Device %S\n", DeviceExtension->NumberOfKsAudioDevices, DeviceEntry->DeviceName.Buffer);
127*c2c66affSColin Finck     return Status;
128*c2c66affSColin Finck 
129*c2c66affSColin Finck cleanup:
130*c2c66affSColin Finck     if (DeviceEntry)
131*c2c66affSColin Finck     {
132*c2c66affSColin Finck         if (DeviceEntry->DeviceName.Buffer)
133*c2c66affSColin Finck             FreeItem(DeviceEntry->DeviceName.Buffer);
134*c2c66affSColin Finck 
135*c2c66affSColin Finck         FreeItem(DeviceEntry);
136*c2c66affSColin Finck     }
137*c2c66affSColin Finck 
138*c2c66affSColin Finck     return Status;
139*c2c66affSColin Finck 
140*c2c66affSColin Finck }
141*c2c66affSColin Finck 
142*c2c66affSColin Finck 
143*c2c66affSColin Finck NTSTATUS
144*c2c66affSColin Finck NTAPI
DeviceInterfaceChangeCallback(IN PVOID NotificationStructure,IN PVOID Context)145*c2c66affSColin Finck DeviceInterfaceChangeCallback(
146*c2c66affSColin Finck     IN PVOID NotificationStructure,
147*c2c66affSColin Finck     IN PVOID Context)
148*c2c66affSColin Finck {
149*c2c66affSColin Finck     DEVICE_INTERFACE_CHANGE_NOTIFICATION * Event;
150*c2c66affSColin Finck     NTSTATUS Status = STATUS_SUCCESS;
151*c2c66affSColin Finck     PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
152*c2c66affSColin Finck 
153*c2c66affSColin Finck     Event = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure;
154*c2c66affSColin Finck 
155*c2c66affSColin Finck     if (IsEqualGUIDAligned(&Event->Event,
156*c2c66affSColin Finck                            &GUID_DEVICE_INTERFACE_ARRIVAL))
157*c2c66affSColin Finck     {
158*c2c66affSColin Finck         Status = InsertAudioDevice(DeviceObject, Event->SymbolicLinkName);
159*c2c66affSColin Finck         return Status;
160*c2c66affSColin Finck     }
161*c2c66affSColin Finck     else
162*c2c66affSColin Finck     {
163*c2c66affSColin Finck         DPRINT("Remove interface to audio device!\n");
164*c2c66affSColin Finck         UNIMPLEMENTED;
165*c2c66affSColin Finck         return STATUS_SUCCESS;
166*c2c66affSColin Finck     }
167*c2c66affSColin Finck 
168*c2c66affSColin Finck 
169*c2c66affSColin Finck }
170*c2c66affSColin Finck 
171*c2c66affSColin Finck NTSTATUS
SysAudioRegisterNotifications(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT DeviceObject)172*c2c66affSColin Finck SysAudioRegisterNotifications(
173*c2c66affSColin Finck     IN PDRIVER_OBJECT  DriverObject,
174*c2c66affSColin Finck     IN PDEVICE_OBJECT DeviceObject)
175*c2c66affSColin Finck {
176*c2c66affSColin Finck     NTSTATUS Status;
177*c2c66affSColin Finck     PSYSAUDIODEVEXT DeviceExtension;
178*c2c66affSColin Finck 
179*c2c66affSColin Finck     DeviceExtension = (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension;
180*c2c66affSColin Finck 
181*c2c66affSColin Finck     Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
182*c2c66affSColin Finck                                             PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
183*c2c66affSColin Finck                                             (PVOID)&KS_CATEGORY_AUDIO,
184*c2c66affSColin Finck                                             DriverObject,
185*c2c66affSColin Finck                                             DeviceInterfaceChangeCallback,
186*c2c66affSColin Finck                                             (PVOID)DeviceObject,
187*c2c66affSColin Finck                                             (PVOID*)&DeviceExtension->KsAudioNotificationEntry);
188*c2c66affSColin Finck 
189*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
190*c2c66affSColin Finck     {
191*c2c66affSColin Finck         DPRINT("IoRegisterPlugPlayNotification failed with %x\n", Status);
192*c2c66affSColin Finck     }
193*c2c66affSColin Finck 
194*c2c66affSColin Finck     Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
195*c2c66affSColin Finck                                             PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
196*c2c66affSColin Finck                                             (PVOID)&DMOCATEGORY_ACOUSTIC_ECHO_CANCEL,
197*c2c66affSColin Finck                                             DriverObject,
198*c2c66affSColin Finck                                             DeviceInterfaceChangeCallback,
199*c2c66affSColin Finck                                             (PVOID)DeviceObject,
200*c2c66affSColin Finck                                             (PVOID*)&DeviceExtension->EchoCancelNotificationEntry);
201*c2c66affSColin Finck 
202*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
203*c2c66affSColin Finck     {
204*c2c66affSColin Finck         /* ignore failure for now */
205*c2c66affSColin Finck         DPRINT("IoRegisterPlugPlayNotification failed for DMOCATEGORY_ACOUSTIC_ECHO_CANCEL\n", Status);
206*c2c66affSColin Finck     }
207*c2c66affSColin Finck 
208*c2c66affSColin Finck     return STATUS_SUCCESS;
209*c2c66affSColin Finck }
210*c2c66affSColin Finck 
211*c2c66affSColin Finck 
212*c2c66affSColin Finck 
213*c2c66affSColin Finck NTSTATUS
SysAudioRegisterDeviceInterfaces(IN PDEVICE_OBJECT DeviceObject)214*c2c66affSColin Finck SysAudioRegisterDeviceInterfaces(
215*c2c66affSColin Finck     IN PDEVICE_OBJECT DeviceObject)
216*c2c66affSColin Finck {
217*c2c66affSColin Finck     NTSTATUS Status;
218*c2c66affSColin Finck     UNICODE_STRING SymbolicLink;
219*c2c66affSColin Finck 
220*c2c66affSColin Finck     Status = IoRegisterDeviceInterface(DeviceObject, &KSCATEGORY_PREFERRED_MIDIOUT_DEVICE, NULL, &SymbolicLink);
221*c2c66affSColin Finck     if (NT_SUCCESS(Status))
222*c2c66affSColin Finck     {
223*c2c66affSColin Finck         IoSetDeviceInterfaceState(&SymbolicLink, TRUE);
224*c2c66affSColin Finck         RtlFreeUnicodeString(&SymbolicLink);
225*c2c66affSColin Finck     }
226*c2c66affSColin Finck     else
227*c2c66affSColin Finck     {
228*c2c66affSColin Finck         DPRINT("Failed to register KSCATEGORY_PREFERRED_MIDIOUT_DEVICE interface Status %x\n", Status);
229*c2c66affSColin Finck         return Status;
230*c2c66affSColin Finck     }
231*c2c66affSColin Finck 
232*c2c66affSColin Finck     Status = IoRegisterDeviceInterface(DeviceObject, &KSCATEGORY_PREFERRED_WAVEIN_DEVICE, NULL, &SymbolicLink);
233*c2c66affSColin Finck     if (NT_SUCCESS(Status))
234*c2c66affSColin Finck     {
235*c2c66affSColin Finck         IoSetDeviceInterfaceState(&SymbolicLink, TRUE);
236*c2c66affSColin Finck         RtlFreeUnicodeString(&SymbolicLink);
237*c2c66affSColin Finck     }
238*c2c66affSColin Finck     else
239*c2c66affSColin Finck     {
240*c2c66affSColin Finck         DPRINT("Failed to register KSCATEGORY_PREFERRED_WAVEIN_DEVICE interface Status %x\n", Status);
241*c2c66affSColin Finck         return Status;
242*c2c66affSColin Finck     }
243*c2c66affSColin Finck 
244*c2c66affSColin Finck     Status = IoRegisterDeviceInterface(DeviceObject, &KSCATEGORY_PREFERRED_WAVEOUT_DEVICE, NULL, &SymbolicLink);
245*c2c66affSColin Finck     if (NT_SUCCESS(Status))
246*c2c66affSColin Finck     {
247*c2c66affSColin Finck         IoSetDeviceInterfaceState(&SymbolicLink, TRUE);
248*c2c66affSColin Finck         RtlFreeUnicodeString(&SymbolicLink);
249*c2c66affSColin Finck     }
250*c2c66affSColin Finck     else
251*c2c66affSColin Finck     {
252*c2c66affSColin Finck         DPRINT("Failed to register KSCATEGORY_PREFERRED_WAVEOUT_DEVICE interface Status %x\n", Status);
253*c2c66affSColin Finck     }
254*c2c66affSColin Finck 
255*c2c66affSColin Finck     Status = IoRegisterDeviceInterface(DeviceObject, &KSCATEGORY_SYSAUDIO, NULL, &SymbolicLink);
256*c2c66affSColin Finck     if (NT_SUCCESS(Status))
257*c2c66affSColin Finck     {
258*c2c66affSColin Finck         IoSetDeviceInterfaceState(&SymbolicLink, TRUE);
259*c2c66affSColin Finck         RtlFreeUnicodeString(&SymbolicLink);
260*c2c66affSColin Finck     }
261*c2c66affSColin Finck     else
262*c2c66affSColin Finck     {
263*c2c66affSColin Finck         DPRINT("Failed to register KSCATEGORY_SYSAUDIO interface Status %x\n", Status);
264*c2c66affSColin Finck     }
265*c2c66affSColin Finck 
266*c2c66affSColin Finck     return Status;
267*c2c66affSColin Finck }
268