4363a03b1c344edce21d23d7ae2f42e42366a58d
[reactos.git] / reactos / drivers / wdm / audio / legacy / wdmaud / deviface.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/legacy/wdmaud/deviface.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 */
9
10 #include "wdmaud.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15 NTSTATUS
16 WdmAudOpenSysAudioDevice(
17 IN LPWSTR DeviceName,
18 OUT PHANDLE Handle)
19 {
20 UNICODE_STRING SymbolicLink;
21 OBJECT_ATTRIBUTES ObjectAttributes;
22 IO_STATUS_BLOCK IoStatusBlock;
23 NTSTATUS Status;
24
25 RtlInitUnicodeString(&SymbolicLink, DeviceName);
26 InitializeObjectAttributes(&ObjectAttributes, &SymbolicLink, OBJ_OPENIF | OBJ_KERNEL_HANDLE, NULL, NULL);
27
28 Status = IoCreateFile(Handle,
29 SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
30 &ObjectAttributes,
31 &IoStatusBlock,
32 NULL,
33 0,
34 0,
35 FILE_OPEN,
36 FILE_SYNCHRONOUS_IO_NONALERT,
37 NULL,
38 0,
39 CreateFileTypeNone,
40 NULL,
41 IO_NO_PARAMETER_CHECKING | IO_FORCE_ACCESS_CHECK);
42
43 return Status;
44 }
45
46 NTSTATUS
47 NTAPI
48 DeviceInterfaceChangeCallback(
49 IN PVOID NotificationStructure,
50 IN PVOID Context)
51 {
52 DEVICE_INTERFACE_CHANGE_NOTIFICATION * Event = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure;
53
54 DPRINT1("DeviceInterfaceChangeCallback called %p\n", Event);
55 DbgBreakPoint();
56 return STATUS_SUCCESS;
57 }
58
59 NTSTATUS
60 WdmAudOpenSysAudioDeviceInterfaces(
61 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,
62 IN LPWSTR SymbolicLinkList)
63 {
64 SYSAUDIO_ENTRY * Entry;
65 ULONG Length;
66
67 DPRINT1("WdmAudOpenSysAudioDeviceInterfaces called\n");
68
69 while(*SymbolicLinkList)
70 {
71 Length = wcslen(SymbolicLinkList) + 1;
72 Entry = (SYSAUDIO_ENTRY*)AllocateItem(NonPagedPool, sizeof(SYSAUDIO_ENTRY) + Length * sizeof(WCHAR));
73 if (!Entry)
74 {
75 return STATUS_INSUFFICIENT_RESOURCES;
76 }
77
78 Entry->SymbolicLink.Length = Length * sizeof(WCHAR);
79 Entry->SymbolicLink.MaximumLength = Length * sizeof(WCHAR);
80 Entry->SymbolicLink.Buffer = (LPWSTR) (Entry + 1);
81 wcscpy(Entry->SymbolicLink.Buffer, SymbolicLinkList);
82
83 InsertTailList(&DeviceExtension->SysAudioDeviceList, &Entry->Entry);
84
85 DeviceExtension->NumSysAudioDevices++;
86 SymbolicLinkList += Length;
87 }
88 return STATUS_SUCCESS;
89 }
90
91
92 NTSTATUS
93 WdmAudOpenSysAudioDevices(
94 IN PDEVICE_OBJECT DeviceObject,
95 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
96 {
97 NTSTATUS Status = STATUS_SUCCESS;
98 LPWSTR SymbolicLinkList;
99 SYSAUDIO_ENTRY * Entry;
100 ULONG Length;
101 HANDLE hSysAudio;
102 PFILE_OBJECT FileObject;
103 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\sysaudio\\GLOBAL");
104
105 if (DeviceExtension->DeviceInterfaceSupport)
106 {
107 Status = IoGetDeviceInterfaces(&KSCATEGORY_SYSAUDIO,
108 NULL,
109 0,
110 &SymbolicLinkList);
111
112 if (NT_SUCCESS(Status))
113 {
114 WdmAudOpenSysAudioDeviceInterfaces(DeviceExtension, SymbolicLinkList);
115 FreeItem(SymbolicLinkList);
116 }
117
118
119 Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
120 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
121 (PVOID)&KSCATEGORY_SYSAUDIO,
122 DeviceObject->DriverObject,
123 DeviceInterfaceChangeCallback,
124 (PVOID)DeviceExtension,
125 &DeviceExtension->SysAudioNotification);
126 }
127 else
128 {
129 Entry = (SYSAUDIO_ENTRY*)AllocateItem(NonPagedPool, sizeof(SYSAUDIO_ENTRY));
130 if (!Entry)
131 {
132 return STATUS_INSUFFICIENT_RESOURCES;
133 }
134
135
136 Length = wcslen(DeviceName.Buffer) + 1;
137 Entry->SymbolicLink.Length = 0;
138 Entry->SymbolicLink.MaximumLength = Length * sizeof(WCHAR);
139 Entry->SymbolicLink.Buffer = AllocateItem(NonPagedPool, Entry->SymbolicLink.MaximumLength);
140
141 if (!Entry->SymbolicLink.Buffer)
142 {
143 FreeItem(Entry);
144 return STATUS_INSUFFICIENT_RESOURCES;
145 }
146
147 Status = RtlAppendUnicodeStringToString(&Entry->SymbolicLink, &DeviceName);
148
149 if (!NT_SUCCESS(Status))
150 {
151 FreeItem(Entry->SymbolicLink.Buffer);
152 FreeItem(Entry);
153 return Status;
154 }
155
156 InsertTailList(&DeviceExtension->SysAudioDeviceList, &Entry->Entry);
157 DeviceExtension->NumSysAudioDevices++;
158
159 DPRINT("Opening device %S\n", Entry->SymbolicLink.Buffer);
160 Status = WdmAudOpenSysAudioDevice(Entry->SymbolicLink.Buffer, &hSysAudio);
161 if (!NT_SUCCESS(Status))
162 {
163 DPRINT1("Failed to open sysaudio %x\n", Status);
164 return Status;
165 }
166
167 /* get the file object */
168 Status = ObReferenceObjectByHandle(hSysAudio, FILE_READ_DATA | FILE_WRITE_DATA, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
169 if (!NT_SUCCESS(Status))
170 {
171 DPRINT1("Failed to reference FileObject %x\n", Status);
172 ZwClose(hSysAudio);
173 return Status;
174 }
175 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
176 DeviceExtension->hSysAudio = hSysAudio;
177 DeviceExtension->FileObject = FileObject;
178 }
179
180 return Status;
181 }
182
183 NTSTATUS
184 WdmAudRegisterDeviceInterface(
185 IN PDEVICE_OBJECT PhysicalDeviceObject,
186 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
187 {
188 NTSTATUS Status;
189 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\wdmaud");
190 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\wdmaud");
191 UNICODE_STRING SymbolicLinkName;
192
193 Status = IoRegisterDeviceInterface(PhysicalDeviceObject, &KSCATEGORY_WDMAUD, NULL, &SymbolicLinkName);
194 if (NT_SUCCESS(Status))
195 {
196 IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
197 RtlFreeUnicodeString(&SymbolicLinkName);
198 DeviceExtension->DeviceInterfaceSupport = TRUE;
199 return Status;
200 }
201
202 /* failed to register device interface
203 * create a symbolic link instead
204 */
205 DeviceExtension->DeviceInterfaceSupport = FALSE;
206
207 Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
208 if (!NT_SUCCESS(Status))
209 {
210 IoDeleteDevice(PhysicalDeviceObject); //FIXME
211 DPRINT("Failed to create wdmaud symlink!\n");
212 return Status;
213 }
214
215 return Status;
216 }
217
218 NTSTATUS
219 WdmAudOpenSysaudio(
220 IN PDEVICE_OBJECT DeviceObject,
221 IN PWDMAUD_CLIENT *pClient)
222 {
223 PWDMAUD_CLIENT Client;
224 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
225
226 /* get device extension */
227 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
228
229 if (!DeviceExtension->NumSysAudioDevices)
230 {
231 /* wdmaud failed to open sysaudio */
232 return STATUS_UNSUCCESSFUL;
233 }
234
235 /* sanity check */
236 ASSERT(!IsListEmpty(&DeviceExtension->SysAudioDeviceList));
237
238 /* allocate client context struct */
239 Client = AllocateItem(NonPagedPool, sizeof(WDMAUD_CLIENT));
240
241 /* check for allocation failure */
242 if (!Client)
243 {
244 /* not enough memory */
245 return STATUS_INSUFFICIENT_RESOURCES;
246 }
247
248 /* zero client context struct */
249 RtlZeroMemory(Client, sizeof(WDMAUD_CLIENT));
250
251 /* initialize mixer event list */
252 InitializeListHead(&Client->MixerEventList);
253
254 /* store result */
255 *pClient = Client;
256
257 /* insert client into list */
258 ExInterlockedInsertTailList(&DeviceExtension->WdmAudClientList, &Client->Entry, &DeviceExtension->Lock);
259
260 /* done */
261 return STATUS_SUCCESS;
262 }