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