Sync up to trunk head.
[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
22
23 VOID
24 NTAPI
25 SysAudio_Unload(IN PDRIVER_OBJECT DriverObject)
26 {
27 DPRINT("SysAudio_Unload called\n");
28 }
29
30 NTSTATUS
31 NTAPI
32 SysAudio_Shutdown(
33 IN PDEVICE_OBJECT DeviceObject,
34 IN PIRP Irp)
35 {
36 PKSAUDIO_DEVICE_ENTRY DeviceEntry;
37 PSYSAUDIODEVEXT DeviceExtension;
38 PLIST_ENTRY Entry;
39
40 DPRINT("SysAudio_Shutdown called\n");
41
42 DeviceExtension = (PSYSAUDIODEVEXT)DeviceObject->DeviceExtension;
43
44 while(!IsListEmpty(&DeviceExtension->KsAudioDeviceList))
45 {
46 Entry = RemoveHeadList(&DeviceExtension->KsAudioDeviceList);
47 DeviceEntry = (PKSAUDIO_DEVICE_ENTRY)CONTAINING_RECORD(Entry, KSAUDIO_DEVICE_ENTRY, Entry);
48
49 DPRINT("Freeing item %wZ\n", &DeviceEntry->DeviceName);
50
51 /* dereference audio device file object */
52 ObDereferenceObject(DeviceEntry->FileObject);
53
54 /* close audio device handle */
55 ZwClose(DeviceEntry->Handle);
56
57 /* free device string */
58 RtlFreeUnicodeString(&DeviceEntry->DeviceName);
59
60 /* free audio device entry */
61 ExFreePool(DeviceEntry);
62 }
63
64 Irp->IoStatus.Information = 0;
65 Irp->IoStatus.Status = STATUS_SUCCESS;
66 IoCompleteRequest(Irp, IO_NO_INCREMENT);
67 return STATUS_SUCCESS;
68 }
69
70
71 NTSTATUS
72 NTAPI
73 SysAudio_Pnp(
74 IN PDEVICE_OBJECT DeviceObject,
75 IN PIRP Irp)
76 {
77 PIO_STACK_LOCATION IrpStack;
78 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\sysaudio");
79 SYSAUDIODEVEXT *DeviceExtension;
80
81 /* Get current irp stack */
82 IrpStack = IoGetCurrentIrpStackLocation(Irp);
83
84 /* Fetch the device extension */
85 DeviceExtension = (SYSAUDIODEVEXT*)DeviceObject->DeviceExtension;
86 ASSERT(DeviceExtension);
87
88 if (IrpStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
89 {
90 /* Unregister the echo cancel hook */
91 if (DeviceExtension->EchoCancelNotificationEntry)
92 IoUnregisterPlugPlayNotification(DeviceExtension->EchoCancelNotificationEntry);
93
94 /* Unregister the ks audio hook */
95 if (DeviceExtension->KsAudioNotificationEntry)
96 IoUnregisterPlugPlayNotification(DeviceExtension->KsAudioNotificationEntry);
97
98 /* Destroy our symbolic link */
99 IoDeleteSymbolicLink(&SymlinkName);
100 }
101 else if (IrpStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
102 {
103 /* Sysaudio can not be disabled */
104 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
105 }
106
107 /* Perform default pnp actions */
108 return KsDefaultDispatchPnp(DeviceObject, Irp);
109 }
110
111 NTSTATUS
112 NTAPI
113 SysAudio_InstallDevice(
114 IN PDRIVER_OBJECT DriverObject)
115 {
116 NTSTATUS Status;
117 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\sysaudio");
118 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\sysaudio");
119 PDEVICE_OBJECT DeviceObject;
120 SYSAUDIODEVEXT *DeviceExtension;
121
122
123 DPRINT("SysAudio_InstallDevice called\n");
124
125 /* Create the device */
126 Status = IoCreateDevice(DriverObject,
127 sizeof(SYSAUDIODEVEXT),
128 &DeviceName,
129 FILE_DEVICE_KS,
130 0,
131 FALSE,
132 &DeviceObject);
133
134 /* Check for success */
135 if (!NT_SUCCESS(Status))
136 {
137 DPRINT("Failed to create \\Device\\sysaudio !\n");
138 return Status;
139 }
140
141 /* Register device interfaces */
142 Status = SysAudioRegisterDeviceInterfaces(DeviceObject);
143 if (!NT_SUCCESS(Status))
144 {
145 /* Failed to register
146 * Create a hack interface
147 */
148 Status = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
149 if (!NT_SUCCESS(Status))
150 {
151 IoDeleteDevice(DeviceObject);
152 DPRINT1("Failed to create sysaudio symlink!\n");
153 return Status;
154 }
155 }
156 /* Acquire device extension */
157 DeviceExtension = (SYSAUDIODEVEXT*)DeviceObject->DeviceExtension;
158 /* Initialize device extension */
159 RtlZeroMemory(DeviceExtension, sizeof(SYSAUDIODEVEXT));
160
161 /* Initialize the mutex */
162 KeInitializeSpinLock(&DeviceExtension->Lock);
163
164 /* Initialize the ks audio device list */
165 InitializeListHead(&DeviceExtension->KsAudioDeviceList);
166
167 /* Allocate kernel streaming device header */
168 Status = SysAudioAllocateDeviceHeader(DeviceExtension);
169 if (!NT_SUCCESS(Status))
170 {
171 DPRINT1("KsAllocateDeviceHeader failed with %x\n", Status);
172 goto cleanup;
173 }
174
175 /* Register device notification hooks */
176 Status = SysAudioRegisterNotifications(DriverObject,
177 DeviceObject);
178 if (!NT_SUCCESS(Status))
179 {
180 DPRINT1("Failed to register device notifications\n");
181 goto cleanup;
182 }
183
184 /* Load kmixer */
185 Status = SysAudioOpenKMixer(DeviceExtension);
186 if (!NT_SUCCESS(Status))
187 {
188 DPRINT1("SysAudioOpenKMixer failed with %x\n", Status);
189 goto cleanup;
190 }
191
192 /* set io flags */
193 DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
194 /* clear initializing flag */
195 DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
196
197 /* register shutdown notfication */
198 IoRegisterShutdownNotification(DeviceObject);
199
200
201 /* Done */
202 return STATUS_SUCCESS;
203
204 cleanup:
205
206 if (DeviceExtension->KsAudioNotificationEntry)
207 IoUnregisterPlugPlayNotification(DeviceExtension->KsAudioNotificationEntry);
208
209 if (DeviceExtension->EchoCancelNotificationEntry)
210 IoUnregisterPlugPlayNotification(DeviceExtension->EchoCancelNotificationEntry);
211
212 IoDeleteSymbolicLink(&SymlinkName);
213 IoDeleteDevice(DeviceObject);
214 return Status;
215 }
216
217 NTSTATUS
218 NTAPI
219 DriverEntry(
220 IN PDRIVER_OBJECT DriverObject,
221 IN PUNICODE_STRING RegistryPath)
222 {
223 DPRINT("System audio graph builder (sysaudio) started\n");
224
225 /* Let ks handle these */
226 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CREATE);
227 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CLOSE);
228 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_WRITE);
229 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_DEVICE_CONTROL);
230
231 /* Let ks handle these */
232 DriverObject->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower;
233 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp;
234
235 /* Use provided ks unload function */
236 DriverObject->DriverUnload = KsNullDriverUnload;
237
238 /* Sysaudio needs to do work on pnp, so handle it */
239 DriverObject->MajorFunction[IRP_MJ_PNP] = SysAudio_Pnp;
240 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = SysAudio_Shutdown;
241
242 /* Call our initialization function */
243 return SysAudio_InstallDevice(DriverObject);
244 }