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
WdmAudOpenSysAudioDevice(IN LPWSTR DeviceName,OUT PHANDLE Handle)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
DeviceInterfaceChangeCallback(IN PVOID NotificationStructure,IN PVOID Context)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
WdmAudOpenSysAudioDeviceInterfaces(IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,IN LPWSTR SymbolicLinkList)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
WdmAudOpenSysAudioDevices(IN PDEVICE_OBJECT DeviceObject,IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)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             DPRINT("Opening device %S\n", Entry->SymbolicLink.Buffer);
157             Status = WdmAudOpenSysAudioDevice(Entry->SymbolicLink.Buffer, &hSysAudio);
158             if (!NT_SUCCESS(Status))
159             {
160                 DPRINT1("Failed to open sysaudio %x\n", Status);
161                 FreeItem(Entry->SymbolicLink.Buffer);
162                 FreeItem(Entry);
163                 return Status;
164             }
165 
166             InsertTailList(&DeviceExtension->SysAudioDeviceList, &Entry->Entry);
167             DeviceExtension->NumSysAudioDevices++;
168 
169             /* get the file object */
170             Status = ObReferenceObjectByHandle(hSysAudio, FILE_READ_DATA | FILE_WRITE_DATA, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
171             if (!NT_SUCCESS(Status))
172             {
173                 DPRINT1("Failed to reference FileObject %x\n", Status);
174                 ZwClose(hSysAudio);
175                 return Status;
176             }
177             DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
178             DeviceExtension->hSysAudio = hSysAudio;
179             DeviceExtension->FileObject = FileObject;
180     }
181 
182     return Status;
183 }
184 
185 NTSTATUS
WdmAudRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject,IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)186 WdmAudRegisterDeviceInterface(
187     IN PDEVICE_OBJECT PhysicalDeviceObject,
188     IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
189 {
190     NTSTATUS Status;
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     return Status;
203 }
204 
205 NTSTATUS
WdmAudOpenSysaudio(IN PDEVICE_OBJECT DeviceObject,IN PWDMAUD_CLIENT * pClient)206 WdmAudOpenSysaudio(
207     IN PDEVICE_OBJECT DeviceObject,
208     IN PWDMAUD_CLIENT *pClient)
209 {
210     PWDMAUD_CLIENT Client;
211     PWDMAUD_DEVICE_EXTENSION DeviceExtension;
212 
213     /* get device extension */
214     DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
215 
216     if (!DeviceExtension->NumSysAudioDevices)
217     {
218         /* wdmaud failed to open sysaudio */
219         return STATUS_UNSUCCESSFUL;
220     }
221 
222     /* sanity check */
223     ASSERT(!IsListEmpty(&DeviceExtension->SysAudioDeviceList));
224 
225     /* allocate client context struct */
226     Client = AllocateItem(NonPagedPool, sizeof(WDMAUD_CLIENT));
227 
228     /* check for allocation failure */
229     if (!Client)
230     {
231         /* not enough memory */
232         return STATUS_INSUFFICIENT_RESOURCES;
233     }
234 
235     /* zero client context struct */
236     RtlZeroMemory(Client, sizeof(WDMAUD_CLIENT));
237 
238     /* initialize mixer event list */
239     InitializeListHead(&Client->MixerEventList);
240 
241     /* store result */
242     *pClient = Client;
243 
244     /* insert client into list */
245     ExInterlockedInsertTailList(&DeviceExtension->WdmAudClientList, &Client->Entry, &DeviceExtension->Lock);
246 
247     /* done */
248     return STATUS_SUCCESS;
249 }
250