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