[SHELL/EXPERIMENTS]
[reactos.git] / drivers / wdm / audio / legacy / wdmaud / entry.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/legacy/wdmaud/main.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 const GUID KSCATEGORY_SYSAUDIO = {0xA7C7A5B1L, 0x5AF3, 0x11D1, {0x9C, 0xED, 0x00, 0xA0, 0x24, 0xBF, 0x04, 0x07}};
16 const GUID KSCATEGORY_WDMAUD = {0x3E227E76L, 0x690D, 0x11D2, {0x81, 0x61, 0x00, 0x00, 0xF8, 0x77, 0x5B, 0xF1}};
17
18 IO_WORKITEM_ROUTINE WdmAudInitWorkerRoutine;
19 IO_TIMER_ROUTINE WdmAudTimerRoutine;
20
21 VOID
22 NTAPI
23 WdmAudInitWorkerRoutine(
24 IN PDEVICE_OBJECT DeviceObject,
25 IN PVOID Context)
26 {
27 NTSTATUS Status;
28 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
29 ULONG DeviceCount;
30
31 /* get device extension */
32 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
33
34 /* get device count */
35 DeviceCount = GetSysAudioDeviceCount(DeviceObject);
36
37 DPRINT("WdmAudInitWorkerRoutine SysAudioDeviceCount %ld\n", DeviceCount);
38
39 /* was a device added / removed */
40 if (DeviceCount != DeviceExtension->SysAudioDeviceCount)
41 {
42 /* init mmixer library */
43 Status = WdmAudMixerInitialize(DeviceObject);
44 DPRINT("WdmAudMixerInitialize Status %x WaveIn %lu WaveOut %lu Mixer %lu\n", Status, WdmAudGetWaveInDeviceCount(), WdmAudGetWaveOutDeviceCount(), WdmAudGetMixerDeviceCount());
45
46 /* store sysaudio device count */
47 DeviceExtension->SysAudioDeviceCount = DeviceCount;
48 }
49
50 /* signal completion */
51 KeSetEvent(&DeviceExtension->InitializationCompletionEvent, IO_NO_INCREMENT, FALSE);
52
53 /* reset work item status indicator */
54 InterlockedDecrement((volatile long *)&DeviceExtension->WorkItemActive);
55 }
56
57 VOID
58 NTAPI
59 WdmAudTimerRoutine(
60 IN PDEVICE_OBJECT DeviceObject,
61 IN PVOID Context)
62 {
63 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
64
65 /* get device extension */
66 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
67
68 if (InterlockedCompareExchange((volatile long *)&DeviceExtension->WorkItemActive, 1, 0) == 0)
69 {
70 /* queue work item */
71 IoQueueWorkItem(DeviceExtension->WorkItem, WdmAudInitWorkerRoutine, DelayedWorkQueue, (PVOID)DeviceExtension);
72 }
73 }
74
75 NTSTATUS
76 NTAPI
77 WdmAudInstallDevice(
78 IN PDRIVER_OBJECT DriverObject)
79 {
80 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\wdmaud");
81 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\wdmaud");
82 PDEVICE_OBJECT DeviceObject;
83 NTSTATUS Status;
84 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
85
86 DPRINT("WdmAudInstallDevice called\n");
87
88 Status = IoCreateDevice(DriverObject,
89 sizeof(WDMAUD_DEVICE_EXTENSION),
90 &DeviceName,
91 FILE_DEVICE_KS,
92 0,
93 FALSE,
94 &DeviceObject);
95
96 if (!NT_SUCCESS(Status))
97 {
98 DPRINT1("IoCreateDevice failed with %x\n", Status);
99 return Status;
100 }
101
102 /* get device extension */
103 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
104 RtlZeroMemory(DeviceExtension, sizeof(WDMAUD_DEVICE_EXTENSION));
105
106 /* allocate work item */
107 DeviceExtension->WorkItem = IoAllocateWorkItem(DeviceObject);
108 if (!DeviceExtension->WorkItem)
109 {
110 /* failed to allocate work item */
111 IoDeleteDevice(DeviceObject);
112 return STATUS_INSUFFICIENT_RESOURCES;
113 }
114
115 /* register device interfaces */
116 Status = WdmAudRegisterDeviceInterface(DeviceObject, DeviceExtension);
117 if (!NT_SUCCESS(Status))
118 {
119 DPRINT1("WdmRegisterDeviceInterface failed with %x\n", Status);
120 IoDeleteDevice(DeviceObject);
121 return Status;
122 }
123
124 /* initialize sysaudio device list */
125 InitializeListHead(&DeviceExtension->SysAudioDeviceList);
126
127 /* initialize client context device list */
128 InitializeListHead(&DeviceExtension->WdmAudClientList);
129
130 /* initialize spinlock */
131 KeInitializeSpinLock(&DeviceExtension->Lock);
132
133 /* initialization completion event */
134 KeInitializeEvent(&DeviceExtension->InitializationCompletionEvent, NotificationEvent, FALSE);
135
136 /* initialize timer */
137 IoInitializeTimer(DeviceObject, WdmAudTimerRoutine, (PVOID)WdmAudTimerRoutine);
138
139 /* find available sysaudio devices */
140 Status = WdmAudOpenSysAudioDevices(DeviceObject, DeviceExtension);
141 if (!NT_SUCCESS(Status))
142 {
143 DPRINT1("WdmAudOpenSysAudioDevices failed with %x\n", Status);
144 IoDeleteSymbolicLink(&SymlinkName);
145 IoDeleteDevice(DeviceObject);
146 return Status;
147 }
148
149 /* allocate ks device header */
150 Status = KsAllocateDeviceHeader(&DeviceExtension->DeviceHeader, 0, NULL);
151 if (!NT_SUCCESS(Status))
152 {
153 DPRINT1("KsAllocateDeviceHeader failed with %x\n", Status);
154 IoDeleteSymbolicLink(&SymlinkName);
155 IoDeleteDevice(DeviceObject);
156 return Status;
157 }
158
159 /* start the timer */
160 IoStartTimer(DeviceObject);
161
162 DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
163 DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
164
165 return STATUS_SUCCESS;
166 }
167
168 VOID
169 NTAPI
170 WdmAudUnload(
171 IN PDRIVER_OBJECT driver)
172 {
173 DPRINT("WdmAudUnload called\n");
174 }
175
176 NTSTATUS
177 NTAPI
178 WdmAudPnp(
179 IN PDEVICE_OBJECT DeviceObject,
180 IN PIRP Irp)
181 {
182 PIO_STACK_LOCATION IrpStack;
183
184 DPRINT("WdmAudPnp called\n");
185
186 IrpStack = IoGetCurrentIrpStackLocation(Irp);
187
188 if (IrpStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
189 {
190 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
191 return KsDefaultDispatchPnp(DeviceObject, Irp);
192 }
193 return KsDefaultDispatchPnp(DeviceObject, Irp);
194 }
195
196
197 NTSTATUS
198 NTAPI
199 WdmAudCreate(
200 IN PDEVICE_OBJECT DeviceObject,
201 IN PIRP Irp)
202 {
203 NTSTATUS Status;
204 PIO_STACK_LOCATION IoStack;
205 PWDMAUD_CLIENT pClient;
206 //PWDMAUD_DEVICE_EXTENSION DeviceExtension;
207
208 /* get device extension */
209 //DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
210
211 #if KS_IMPLEMENTED
212 Status = KsReferenceSoftwareBusObject((KSDEVICE_HEADER)DeviceObject->DeviceExtension);
213 if (!NT_SUCCESS(Status))
214 {
215 DPRINT1("KsReferenceSoftwareBusObject failed with %x\n", Status);
216 return Status;
217 }
218 #endif
219
220 Status = WdmAudOpenSysaudio(DeviceObject, &pClient);
221 if (!NT_SUCCESS(Status))
222 {
223 DPRINT1("Failed to open sysaudio!\n");
224
225 /* complete and forget */
226 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
227 IoCompleteRequest(Irp, IO_NO_INCREMENT);
228 /* done */
229 return STATUS_UNSUCCESSFUL;
230 }
231
232 IoStack = IoGetCurrentIrpStackLocation(Irp);
233 ASSERT(IoStack->FileObject);
234
235 /* store client context in file object */
236 IoStack->FileObject->FsContext = pClient;
237 Status = STATUS_SUCCESS;
238
239 Irp->IoStatus.Status = Status;
240 Irp->IoStatus.Information = 0;
241 IoCompleteRequest(Irp, IO_NO_INCREMENT);
242
243 return Status;
244 }
245
246 NTSTATUS
247 NTAPI
248 WdmAudClose(
249 IN PDEVICE_OBJECT DeviceObject,
250 IN PIRP Irp)
251 {
252 /* nothing to do complete request */
253 #if KS_IMPLEMENTED
254 Status = KsDereferenceSoftwareBusObject(DeviceExtension->DeviceHeader);
255
256 if (NT_SUCCESS(Status))
257 {
258 if (DeviceExtension->SysAudioNotification)
259 Status = IoUnregisterPlugPlayNotification(DeviceExtension->SysAudioNotification);
260 }
261 #endif
262
263 Irp->IoStatus.Status = STATUS_SUCCESS;
264 Irp->IoStatus.Information = 0;
265 IoCompleteRequest(Irp, IO_NO_INCREMENT);
266
267 /* done */
268 return STATUS_SUCCESS;
269 }
270
271 NTSTATUS
272 NTAPI
273 WdmAudCleanup(
274 IN PDEVICE_OBJECT DeviceObject,
275 IN PIRP Irp)
276 {
277 PIO_STACK_LOCATION IoStack;
278 PWDMAUD_CLIENT pClient;
279 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
280 ULONG Index;
281 KIRQL OldIrql;
282
283 /* get device extension */
284 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
285
286 /* get current irp stack location */
287 IoStack = IoGetCurrentIrpStackLocation(Irp);
288
289 /* sanity check */
290 ASSERT(IoStack->FileObject);
291
292 /* get client context struct */
293 pClient = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
294
295 /* sanity check */
296 ASSERT(pClient);
297
298 /* acquire client context list lock */
299 KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
300
301 /* remove entry */
302 RemoveEntryList(&pClient->Entry);
303
304 /* release lock */
305 KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
306
307 /* check if all audio pins have been closed */
308 for (Index = 0; Index < pClient->NumPins; Index++)
309 {
310 DPRINT("Index %u Pin %p Type %x\n", Index, pClient->hPins[Index].Handle, pClient->hPins[Index].Type);
311 if (pClient->hPins[Index].Handle && pClient->hPins[Index].Type != MIXER_DEVICE_TYPE)
312 {
313 /* found an still open audio pin */
314 ZwClose(pClient->hPins[Index].Handle);
315 }
316 }
317
318 /* free pin array */
319 if (pClient->hPins)
320 FreeItem(pClient->hPins);
321
322 /* free client context struct */
323 FreeItem(pClient);
324
325 /* clear old client pointer */
326 IoStack->FileObject->FsContext = NULL;
327
328 /* complete request */
329 Irp->IoStatus.Status = STATUS_SUCCESS;
330 Irp->IoStatus.Information = 0;
331 IoCompleteRequest(Irp, IO_NO_INCREMENT);
332
333 /* done */
334 return STATUS_SUCCESS;
335 }
336
337 NTSTATUS
338 NTAPI
339 DriverEntry(
340 IN PDRIVER_OBJECT Driver,
341 IN PUNICODE_STRING Registry_path
342 )
343 {
344 DPRINT("Wdmaud.sys loaded\n");
345
346 Driver->DriverUnload = WdmAudUnload;
347
348 Driver->MajorFunction[IRP_MJ_CREATE] = WdmAudCreate;
349 Driver->MajorFunction[IRP_MJ_CLOSE] = WdmAudClose;
350 Driver->MajorFunction[IRP_MJ_PNP] = WdmAudPnp;
351 Driver->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp;
352 Driver->MajorFunction[IRP_MJ_CLEANUP] = WdmAudCleanup;
353 Driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = WdmAudDeviceControl;
354 Driver->MajorFunction[IRP_MJ_WRITE] = WdmAudReadWrite;
355 Driver->MajorFunction[IRP_MJ_READ] = WdmAudReadWrite;
356 Driver->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower;
357
358 return WdmAudInstallDevice(Driver);
359 }