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