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