d191a97c2db7ac4b828ecb635b3dc608e6d3c4da
[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 #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 Length = wcslen(DeviceName.Buffer) + 1;
126 Entry = (SYSAUDIO_ENTRY*)AllocateItem(NonPagedPool, sizeof(SYSAUDIO_ENTRY) + Length * sizeof(WCHAR));
127 if (!Entry)
128 {
129 return STATUS_INSUFFICIENT_RESOURCES;
130 }
131
132 Entry->SymbolicLink.Length = Entry->SymbolicLink.MaximumLength = Length * sizeof(WCHAR);
133 Entry->SymbolicLink.MaximumLength += sizeof(WCHAR);
134 Entry->SymbolicLink.Buffer = (LPWSTR) (Entry + 1);
135
136 wcscpy(Entry->SymbolicLink.Buffer, DeviceName.Buffer);
137
138 InsertTailList(&DeviceExtension->SysAudioDeviceList, &Entry->Entry);
139 DeviceExtension->NumSysAudioDevices++;
140
141 DPRINT("Opening device %S\n", Entry->SymbolicLink.Buffer);
142 Status = WdmAudOpenSysAudioDevice(Entry->SymbolicLink.Buffer, &hSysAudio);
143 if (!NT_SUCCESS(Status))
144 {
145 DPRINT1("Failed to open sysaudio %x\n", Status);
146 return Status;
147 }
148
149 /* get the file object */
150 Status = ObReferenceObjectByHandle(hSysAudio, FILE_READ_DATA | FILE_WRITE_DATA, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
151 if (!NT_SUCCESS(Status))
152 {
153 DPRINT1("Failed to reference FileObject %x\n", Status);
154 ZwClose(hSysAudio);
155 return Status;
156 }
157 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
158 DeviceExtension->hSysAudio = hSysAudio;
159 DeviceExtension->FileObject = FileObject;
160 }
161
162 return Status;
163 }
164
165 NTSTATUS
166 WdmAudRegisterDeviceInterface(
167 IN PDEVICE_OBJECT PhysicalDeviceObject,
168 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
169 {
170 NTSTATUS Status;
171 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\wdmaud");
172 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\wdmaud");
173 UNICODE_STRING SymbolicLinkName;
174
175 Status = IoRegisterDeviceInterface(PhysicalDeviceObject, &KSCATEGORY_WDMAUD, NULL, &SymbolicLinkName);
176 if (NT_SUCCESS(Status))
177 {
178 IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
179 RtlFreeUnicodeString(&SymbolicLinkName);
180 DeviceExtension->DeviceInterfaceSupport = TRUE;
181 return Status;
182 }
183
184 /* failed to register device interface
185 * create a symbolic link instead
186 */
187 DeviceExtension->DeviceInterfaceSupport = FALSE;
188
189 Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
190 if (!NT_SUCCESS(Status))
191 {
192 IoDeleteDevice(PhysicalDeviceObject); //FIXME
193 DPRINT("Failed to create wdmaud symlink!\n");
194 return Status;
195 }
196
197 return Status;
198 }
199
200 NTSTATUS
201 WdmAudOpenSysaudio(
202 IN PDEVICE_OBJECT DeviceObject,
203 IN PWDMAUD_CLIENT *pClient)
204 {
205 PWDMAUD_CLIENT Client;
206 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
207
208 /* get device extension */
209 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
210
211 if (!DeviceExtension->NumSysAudioDevices)
212 {
213 /* wdmaud failed to open sysaudio */
214 return STATUS_UNSUCCESSFUL;
215 }
216
217 /* sanity check */
218 ASSERT(!IsListEmpty(&DeviceExtension->SysAudioDeviceList));
219
220 /* allocate client context struct */
221 Client = AllocateItem(NonPagedPool, sizeof(WDMAUD_CLIENT));
222
223 /* check for allocation failure */
224 if (!Client)
225 {
226 /* not enough memory */
227 return STATUS_INSUFFICIENT_RESOURCES;
228 }
229
230 /* zero client context struct */
231 RtlZeroMemory(Client, sizeof(WDMAUD_CLIENT));
232
233 /* initialize mixer event list */
234 InitializeListHead(&Client->MixerEventList);
235
236 /* store result */
237 *pClient = Client;
238
239 /* insert client into list */
240 ExInterlockedInsertTailList(&DeviceExtension->WdmAudClientList, &Client->Entry, &DeviceExtension->Lock);
241
242 /* done */
243 return STATUS_SUCCESS;
244 }
245
246
247