xref: /reactos/drivers/wdm/audio/sysaudio/main.c (revision 8a978a17)
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 }
271