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