2df6f55a84b2cbb64af608b55f01c744cba58223
[reactos.git] / drivers / wdm / audio / sysaudio / main.c
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
15 const GUID KSCATEGORY_SYSAUDIO = {0xA7C7A5B1L, 0x5AF3, 0x11D1, {0x9C, 0xED, 0x00, 0xA0, 0x24, 0xBF, 0x04, 0x07}};
16 const GUID KSCATEGORY_AUDIO_DEVICE = {0xFBF6F530L, 0x07B9, 0x11D2, {0xA7, 0x1E, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}};
17 const GUID KSCATEGORY_PREFERRED_WAVEOUT_DEVICE = {0xD6C5066EL, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}};
18 const GUID KSCATEGORY_PREFERRED_WAVEIN_DEVICE = {0xD6C50671L, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}};
19 const GUID KSCATEGORY_PREFERRED_MIDIOUT_DEVICE = {0xD6C50674L, 0x72C1, 0x11D2, {0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88}};
20
21 PVOID
22 AllocateItem(
23 IN POOL_TYPE PoolType,
24 IN SIZE_T NumberOfBytes)
25 {
26 PVOID Item = ExAllocatePool(PoolType, NumberOfBytes);
27 if (!Item)
28 return Item;
29
30 RtlZeroMemory(Item, NumberOfBytes);
31 return Item;
32 }
33
34 VOID
35 FreeItem(
36 IN PVOID Item)
37 {
38 ExFreePool(Item);
39 }
40
41
42 VOID
43 NTAPI
44 SysAudio_Unload(IN PDRIVER_OBJECT DriverObject)
45 {
46 DPRINT("SysAudio_Unload called\n");
47 }
48
49 NTSTATUS
50 NTAPI
51 SysAudio_Shutdown(
52 IN PDEVICE_OBJECT DeviceObject,
53 IN PIRP Irp)
54 {
55 PKSAUDIO_DEVICE_ENTRY DeviceEntry;
56 PSYSAUDIODEVEXT DeviceExtension;
57 PLIST_ENTRY Entry;
58
59 DPRINT("SysAudio_Shutdown called\n");
60
61 DeviceExtension = (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension;
62
63 while(!IsListEmpty(&DeviceExtension->KsAudioDeviceList))
64 {
65 Entry = RemoveHeadList(&DeviceExtension->KsAudioDeviceList);
66 DeviceEntry = (PKSAUDIO_DEVICE_ENTRY)CONTAINING_RECORD(Entry, KSAUDIO_DEVICE_ENTRY, Entry);
67
68 DPRINT("Freeing item %wZ\n", &DeviceEntry->DeviceName);
69
70 /* dereference audio device file object */
71 ObDereferenceObject(DeviceEntry->FileObject);
72
73 /* close audio device handle */
74 ZwClose(DeviceEntry->Handle);
75
76 /* free device string */
77 RtlFreeUnicodeString(&DeviceEntry->DeviceName);
78
79 /* free audio device entry */
80 FreeItem(DeviceEntry);
81 }
82
83 Irp->IoStatus.Information = 0;
84 Irp->IoStatus.Status = STATUS_SUCCESS;
85 IoCompleteRequest(Irp, IO_NO_INCREMENT);
86 return STATUS_SUCCESS;
87 }
88
89
90 NTSTATUS
91 NTAPI
92 SysAudio_Pnp(
93 IN PDEVICE_OBJECT DeviceObject,
94 IN PIRP Irp)
95 {
96 PIO_STACK_LOCATION IrpStack;
97 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\sysaudio");
98 SYSAUDIODEVEXT *DeviceExtension;
99
100 /* Get current irp stack */
101 IrpStack = IoGetCurrentIrpStackLocation(Irp);
102
103 /* Fetch the device extension */
104 DeviceExtension = (SYSAUDIODEVEXT*)DeviceObject->DeviceExtension;
105 ASSERT(DeviceExtension);
106
107 if (IrpStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
108 {
109 /* Unregister the echo cancel hook */
110 if (DeviceExtension->EchoCancelNotificationEntry)
111 IoUnregisterPlugPlayNotification(DeviceExtension->EchoCancelNotificationEntry);
112
113 /* Unregister the ks audio hook */
114 if (DeviceExtension->KsAudioNotificationEntry)
115 IoUnregisterPlugPlayNotification(DeviceExtension->KsAudioNotificationEntry);
116
117 /* Destroy our symbolic link */
118 IoDeleteSymbolicLink(&SymlinkName);
119 }
120 else if (IrpStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
121 {
122 /* Sysaudio can not be disabled */
123 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
124 }
125
126 /* Perform default pnp actions */
127 return KsDefaultDispatchPnp(DeviceObject, Irp);
128 }
129
130 NTSTATUS
131 NTAPI
132 SysAudio_InstallDevice(
133 IN PDRIVER_OBJECT DriverObject)
134 {
135 NTSTATUS Status;
136 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\sysaudio");
137 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\sysaudio");
138 PDEVICE_OBJECT DeviceObject;
139 SYSAUDIODEVEXT *DeviceExtension;
140
141
142 DPRINT("SysAudio_InstallDevice called\n");
143
144 /* Create the device */
145 Status = IoCreateDevice(DriverObject,
146 sizeof(SYSAUDIODEVEXT),
147 &DeviceName,
148 FILE_DEVICE_KS,
149 0,
150 FALSE,
151 &DeviceObject);
152
153 /* Check for success */
154 if (!NT_SUCCESS(Status))
155 {
156 DPRINT("Failed to create \\Device\\sysaudio !\n");
157 return Status;
158 }
159
160 /* Register device interfaces */
161 Status = SysAudioRegisterDeviceInterfaces(DeviceObject);
162 if (!NT_SUCCESS(Status))
163 {
164 /* Failed to register
165 * Create a hack interface
166 */
167 Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
168 if (!NT_SUCCESS(Status))
169 {
170 IoDeleteDevice(DeviceObject);
171 DPRINT1("Failed to create sysaudio symlink!\n");
172 return Status;
173 }
174 }
175 /* Acquire device extension */
176 DeviceExtension = (SYSAUDIODEVEXT*)DeviceObject->DeviceExtension;
177 /* Initialize device extension */
178 RtlZeroMemory(DeviceExtension, sizeof(SYSAUDIODEVEXT));
179
180 /* Initialize the mutex */
181 KeInitializeSpinLock(&DeviceExtension->Lock);
182
183 /* Initialize the ks audio device list */
184 InitializeListHead(&DeviceExtension->KsAudioDeviceList);
185
186 /* Allocate kernel streaming device header */
187 Status = SysAudioAllocateDeviceHeader(DeviceExtension);
188 if (!NT_SUCCESS(Status))
189 {
190 DPRINT1("KsAllocateDeviceHeader failed with %x\n", Status);
191 goto cleanup;
192 }
193
194 /* Register device notification hooks */
195 Status = SysAudioRegisterNotifications(DriverObject,
196 DeviceObject);
197 if (!NT_SUCCESS(Status))
198 {
199 DPRINT1("Failed to register device notifications\n");
200 goto cleanup;
201 }
202
203 /* Load kmixer */
204 Status = SysAudioOpenKMixer(DeviceExtension);
205 if (!NT_SUCCESS(Status))
206 {
207 DPRINT1("SysAudioOpenKMixer failed with %x\n", Status);
208 goto cleanup;
209 }
210
211 /* set io flags */
212 DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
213 /* clear initializing flag */
214 DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
215
216 /* register shutdown notfication */
217 IoRegisterShutdownNotification(DeviceObject);
218
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
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
261 /* Call our initialization function */
262 return SysAudio_InstallDevice(DriverObject);
263 }