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