1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/sysaudio/main.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 * HISTORY:
9 * 8 Jul 07 Started basic implementation
10 */
11
12 #include "sysaudio.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 #define TAG_SYSAUDIO 'AsyS'
18
19 const GUID KSCATEGORY_SYSAUDIO = {0xA7C7A5B1L, 0x5AF3, 0x11D1, {0x9C, 0xED, 0x00, 0xA0, 0x24, 0xBF, 0x04, 0x07}};
20 const GUID KSCATEGORY_AUDIO_DEVICE = {0xFBF6F530L, 0x07B9, 0x11D2, {0xA7, 0x1E, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}};
21 const GUID KSCATEGORY_PREFERRED_WAVEOUT_DEVICE = {0xD6C5066EL, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}};
22 const GUID KSCATEGORY_PREFERRED_WAVEIN_DEVICE = {0xD6C50671L, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}};
23 const GUID KSCATEGORY_PREFERRED_MIDIOUT_DEVICE = {0xD6C50674L, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}};
24
25 PVOID
AllocateItem(IN POOL_TYPE PoolType,IN SIZE_T NumberOfBytes)26 AllocateItem(
27 IN POOL_TYPE PoolType,
28 IN SIZE_T NumberOfBytes)
29 {
30 return ExAllocatePoolZero(PoolType, NumberOfBytes, TAG_SYSAUDIO);
31 }
32
33 VOID
FreeItem(IN PVOID Item)34 FreeItem(
35 IN PVOID Item)
36 {
37 ExFreePoolWithTag(Item, TAG_SYSAUDIO);
38 }
39
40 VOID
41 NTAPI
SysAudio_Unload(IN PDRIVER_OBJECT DriverObject)42 SysAudio_Unload(IN PDRIVER_OBJECT DriverObject)
43 {
44 DPRINT("SysAudio_Unload called\n");
45 }
46
47 NTSTATUS
48 NTAPI
SysAudio_Shutdown(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)49 SysAudio_Shutdown(
50 IN PDEVICE_OBJECT DeviceObject,
51 IN PIRP Irp)
52 {
53 PKSAUDIO_DEVICE_ENTRY DeviceEntry;
54 PSYSAUDIODEVEXT DeviceExtension;
55 PLIST_ENTRY Entry;
56
57 DPRINT("SysAudio_Shutdown called\n");
58
59 DeviceExtension = (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension;
60
61 while(!IsListEmpty(&DeviceExtension->KsAudioDeviceList))
62 {
63 Entry = RemoveHeadList(&DeviceExtension->KsAudioDeviceList);
64 DeviceEntry = (PKSAUDIO_DEVICE_ENTRY)CONTAINING_RECORD(Entry, KSAUDIO_DEVICE_ENTRY, Entry);
65
66 DPRINT("Freeing item %wZ\n", &DeviceEntry->DeviceName);
67
68 /* dereference audio device file object */
69 ObDereferenceObject(DeviceEntry->FileObject);
70
71 /* close audio device handle */
72 ZwClose(DeviceEntry->Handle);
73
74 /* free device string */
75 RtlFreeUnicodeString(&DeviceEntry->DeviceName);
76
77 /* free audio device entry */
78 FreeItem(DeviceEntry);
79 }
80
81 Irp->IoStatus.Information = 0;
82 Irp->IoStatus.Status = STATUS_SUCCESS;
83 IoCompleteRequest(Irp, IO_NO_INCREMENT);
84 return STATUS_SUCCESS;
85 }
86
87 NTSTATUS
88 NTAPI
SysAudio_Pnp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)89 SysAudio_Pnp(
90 IN PDEVICE_OBJECT DeviceObject,
91 IN PIRP Irp)
92 {
93 PIO_STACK_LOCATION IrpStack;
94 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\sysaudio");
95 SYSAUDIODEVEXT *DeviceExtension;
96
97 /* Get current irp stack */
98 IrpStack = IoGetCurrentIrpStackLocation(Irp);
99
100 /* Fetch the device extension */
101 DeviceExtension = (SYSAUDIODEVEXT*)DeviceObject->DeviceExtension;
102 ASSERT(DeviceExtension);
103
104 if (IrpStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
105 {
106 /* Unregister the echo cancel hook */
107 if (DeviceExtension->EchoCancelNotificationEntry)
108 IoUnregisterPlugPlayNotification(DeviceExtension->EchoCancelNotificationEntry);
109
110 /* Unregister the ks audio hook */
111 if (DeviceExtension->KsAudioNotificationEntry)
112 IoUnregisterPlugPlayNotification(DeviceExtension->KsAudioNotificationEntry);
113
114 /* Destroy our symbolic link */
115 IoDeleteSymbolicLink(&SymlinkName);
116 }
117 else if (IrpStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
118 {
119 /* Sysaudio can not be disabled */
120 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
121 }
122
123 /* Perform default pnp actions */
124 return KsDefaultDispatchPnp(DeviceObject, Irp);
125 }
126
127 NTSTATUS
128 NTAPI
SysAudio_AddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject)129 SysAudio_AddDevice(
130 IN PDRIVER_OBJECT DriverObject,
131 IN PDEVICE_OBJECT PhysicalDeviceObject)
132 {
133 NTSTATUS Status;
134 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\sysaudio");
135 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\sysaudio");
136 PDEVICE_OBJECT DeviceObject, NextDeviceObject;
137 SYSAUDIODEVEXT *DeviceExtension;
138
139 DPRINT("SysAudio_AddDevice called\n");
140
141 /* Create the device */
142 Status = IoCreateDevice(DriverObject,
143 sizeof(SYSAUDIODEVEXT),
144 &DeviceName,
145 FILE_DEVICE_KS,
146 0,
147 FALSE,
148 &DeviceObject);
149
150 /* Check for success */
151 if (!NT_SUCCESS(Status))
152 {
153 DPRINT("Failed to create \\Device\\sysaudio !\n");
154 return Status;
155 }
156
157 /* Register device interfaces */
158 Status = SysAudioRegisterDeviceInterfaces(PhysicalDeviceObject);
159 if (!NT_SUCCESS(Status))
160 {
161 /* Failed to register
162 * Create a hack interface
163 */
164 Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
165 if (!NT_SUCCESS(Status))
166 {
167 IoDeleteDevice(DeviceObject);
168 DPRINT1("Failed to create sysaudio symlink!\n");
169 return Status;
170 }
171 }
172 /* Acquire device extension */
173 DeviceExtension = (SYSAUDIODEVEXT*)DeviceObject->DeviceExtension;
174 /* Initialize device extension */
175 RtlZeroMemory(DeviceExtension, sizeof(SYSAUDIODEVEXT));
176
177 /* Initialize the mutex */
178 KeInitializeSpinLock(&DeviceExtension->Lock);
179
180 /* Initialize the ks audio device list */
181 InitializeListHead(&DeviceExtension->KsAudioDeviceList);
182
183 /* Allocate kernel streaming device header */
184 Status = SysAudioAllocateDeviceHeader(DeviceExtension);
185 if (!NT_SUCCESS(Status))
186 {
187 DPRINT1("KsAllocateDeviceHeader failed with %x\n", Status);
188 goto cleanup;
189 }
190
191 /* Register device notification hooks */
192 Status = SysAudioRegisterNotifications(DriverObject,
193 DeviceObject);
194 if (!NT_SUCCESS(Status))
195 {
196 DPRINT1("Failed to register device notifications\n");
197 goto cleanup;
198 }
199
200 /* Load kmixer */
201 Status = SysAudioOpenKMixer(DeviceExtension);
202 if (!NT_SUCCESS(Status))
203 {
204 DPRINT1("SysAudioOpenKMixer failed with %x\n", Status);
205 goto cleanup;
206 }
207
208 /* set io flags */
209 DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
210 /* clear initializing flag */
211 DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
212
213 /* atttach to device stack */
214 NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
215 KsSetDevicePnpAndBaseObject(DeviceExtension->KsDeviceHeader, NextDeviceObject, DeviceObject);
216
217 /* register shutdown notification */
218 IoRegisterShutdownNotification(DeviceObject);
219
220 /* Done */
221 return STATUS_SUCCESS;
222
223 cleanup:
224
225 if (DeviceExtension->KsAudioNotificationEntry)
226 IoUnregisterPlugPlayNotification(DeviceExtension->KsAudioNotificationEntry);
227
228 if (DeviceExtension->EchoCancelNotificationEntry)
229 IoUnregisterPlugPlayNotification(DeviceExtension->EchoCancelNotificationEntry);
230
231 IoDeleteSymbolicLink(&SymlinkName);
232 IoDeleteDevice(DeviceObject);
233 return Status;
234 }
235
236 NTSTATUS
237 NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)238 DriverEntry(
239 IN PDRIVER_OBJECT DriverObject,
240 IN PUNICODE_STRING RegistryPath)
241 {
242 DPRINT("System audio graph builder (sysaudio) started\n");
243
244 /* Let ks handle these */
245 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CREATE);
246 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CLOSE);
247 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_WRITE);
248 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_DEVICE_CONTROL);
249
250 /* Let ks handle these */
251 DriverObject->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower;
252 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp;
253
254 /* Use provided ks unload function */
255 DriverObject->DriverUnload = KsNullDriverUnload;
256
257 /* Sysaudio needs to do work on pnp, so handle it */
258 DriverObject->MajorFunction[IRP_MJ_PNP] = SysAudio_Pnp;
259 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = SysAudio_Shutdown;
260 DriverObject->DriverExtension->AddDevice = SysAudio_AddDevice;
261
262 /* done */
263 return STATUS_SUCCESS;
264 }
265