Merge from amd64-branch:
[reactos.git] / reactos / 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 #include "wdmaud.h"
10
11 const GUID KSCATEGORY_SYSAUDIO = {0xA7C7A5B1L, 0x5AF3, 0x11D1, {0x9C, 0xED, 0x00, 0xA0, 0x24, 0xBF, 0x04, 0x07}};
12 const GUID KSCATEGORY_WDMAUD = {0x3E227E76L, 0x690D, 0x11D2, {0x81, 0x61, 0x00, 0x00, 0xF8, 0x77, 0x5B, 0xF1}};
13
14 NTSTATUS
15 NTAPI
16 WdmAudInstallDevice(
17 IN PDRIVER_OBJECT DriverObject)
18 {
19 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\wdmaud");
20 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\wdmaud");
21 PDEVICE_OBJECT DeviceObject;
22 NTSTATUS Status;
23 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
24
25 DPRINT("WdmAudInstallDevice called\n");
26
27 Status = IoCreateDevice(DriverObject,
28 sizeof(WDMAUD_DEVICE_EXTENSION),
29 &DeviceName,
30 FILE_DEVICE_KS,
31 0,
32 FALSE,
33 &DeviceObject);
34
35 if (!NT_SUCCESS(Status))
36 {
37 DPRINT1("IoCreateDevice failed with %x\n", Status);
38 return Status;
39 }
40
41 /* clear device extension */
42 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
43 RtlZeroMemory(DeviceExtension, sizeof(WDMAUD_DEVICE_EXTENSION));
44
45 /* register device interfaces */
46 Status = WdmAudRegisterDeviceInterface(DeviceObject, DeviceExtension);
47 if (!NT_SUCCESS(Status))
48 {
49 DPRINT1("WdmRegisterDeviceInterface failed with %x\n", Status);
50 IoDeleteDevice(DeviceObject);
51 return Status;
52 }
53
54 /* initialize sysaudio device list */
55 InitializeListHead(&DeviceExtension->SysAudioDeviceList);
56
57 /* initialize client context device list */
58 InitializeListHead(&DeviceExtension->WdmAudClientList);
59
60 /* initialize spinlock */
61 KeInitializeSpinLock(&DeviceExtension->Lock);
62
63 /* find available sysaudio devices */
64 Status = WdmAudOpenSysAudioDevices(DeviceObject, DeviceExtension);
65 if (!NT_SUCCESS(Status))
66 {
67 DPRINT1("WdmAudOpenSysAudioDevices failed with %x\n", Status);
68 IoDeleteSymbolicLink(&SymlinkName);
69 IoDeleteDevice(DeviceObject);
70 return Status;
71 }
72 /* allocate ks device header */
73 Status = KsAllocateDeviceHeader(&DeviceExtension->DeviceHeader, 0, NULL);
74 if (!NT_SUCCESS(Status))
75 {
76 DPRINT1("KsAllocateDeviceHeader failed with %x\n", Status);
77 IoDeleteSymbolicLink(&SymlinkName);
78 IoDeleteDevice(DeviceObject);
79 return Status;
80 }
81
82 Status = WdmAudMixerInitialize(DeviceObject);
83 DPRINT("WdmAudMixerInitialize Status %x\n", Status);
84 Status = WdmAudWaveInitialize(DeviceObject);
85 DPRINT("WdmAudWaveInitialize Status %x\n", Status);
86
87 DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
88 DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
89
90 return STATUS_SUCCESS;
91 }
92
93 VOID
94 NTAPI
95 WdmAudUnload(
96 IN PDRIVER_OBJECT driver)
97 {
98 DPRINT("WdmAudUnload called\n");
99 }
100
101 NTSTATUS
102 NTAPI
103 WdmAudPnp(
104 IN PDEVICE_OBJECT DeviceObject,
105 IN PIRP Irp)
106 {
107 PIO_STACK_LOCATION IrpStack;
108
109 DPRINT("WdmAudPnp called\n");
110
111 IrpStack = IoGetCurrentIrpStackLocation(Irp);
112
113 if (IrpStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
114 {
115 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
116 return KsDefaultDispatchPnp(DeviceObject, Irp);
117 }
118 return KsDefaultDispatchPnp(DeviceObject, Irp);
119 }
120
121
122 NTSTATUS
123 NTAPI
124 WdmAudCreate(
125 IN PDEVICE_OBJECT DeviceObject,
126 IN PIRP Irp)
127 {
128 NTSTATUS Status;
129 PIO_STACK_LOCATION IoStack;
130 PWDMAUD_CLIENT pClient;
131 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
132
133 /* get device extension */
134 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
135
136 #if KS_IMPLEMENTED
137 Status = KsReferenceSoftwareBusObject((KSDEVICE_HEADER)DeviceObject->DeviceExtension);
138 if (!NT_SUCCESS(Status))
139 {
140 DPRINT1("KsReferenceSoftwareBusObject failed with %x\n", Status);
141 return Status;
142 }
143 #endif
144
145 Status = WdmAudOpenSysaudio(DeviceObject, &pClient);
146 if (!NT_SUCCESS(Status))
147 {
148 DPRINT1("Failed to open sysaudio!\n");
149
150 /* complete and forget */
151 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
152 IoCompleteRequest(Irp, IO_NO_INCREMENT);
153 /* done */
154 return STATUS_UNSUCCESSFUL;
155 }
156
157 IoStack = IoGetCurrentIrpStackLocation(Irp);
158 ASSERT(IoStack->FileObject);
159
160 /* store client context in file object */
161 IoStack->FileObject->FsContext = pClient;
162 Status = STATUS_SUCCESS;
163
164 Irp->IoStatus.Status = Status;
165 Irp->IoStatus.Information = 0;
166 IoCompleteRequest(Irp, IO_NO_INCREMENT);
167
168 return Status;
169 }
170
171 NTSTATUS
172 NTAPI
173 WdmAudClose(
174 IN PDEVICE_OBJECT DeviceObject,
175 IN PIRP Irp)
176 {
177 /* nothing to do complete request */
178 #if KS_IMPLEMENTED
179 Status = KsDereferenceSoftwareBusObject(DeviceExtension->DeviceHeader);
180
181 if (NT_SUCCESS(Status))
182 {
183 if (DeviceExtension->SysAudioNotification)
184 Status = IoUnregisterPlugPlayNotification(DeviceExtension->SysAudioNotification);
185 }
186 #endif
187
188 Irp->IoStatus.Status = STATUS_SUCCESS;
189 Irp->IoStatus.Information = 0;
190 IoCompleteRequest(Irp, IO_NO_INCREMENT);
191
192 /* done */
193 return STATUS_SUCCESS;
194 }
195
196 NTSTATUS
197 NTAPI
198 WdmAudCleanup(
199 IN PDEVICE_OBJECT DeviceObject,
200 IN PIRP Irp)
201 {
202 PIO_STACK_LOCATION IoStack;
203 PWDMAUD_CLIENT pClient;
204 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
205 ULONG Index;
206 KIRQL OldIrql;
207
208 /* get device extension */
209 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
210
211 /* get current irp stack location */
212 IoStack = IoGetCurrentIrpStackLocation(Irp);
213
214 /* sanity check */
215 ASSERT(IoStack->FileObject);
216
217 /* get client context struct */
218 pClient = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
219
220 /* sanity check */
221 ASSERT(pClient);
222
223 /* acquire client context list lock */
224 KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
225
226 /* remove entry */
227 RemoveEntryList(&pClient->Entry);
228
229 /* release lock */
230 KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
231
232 /* check if all audio pins have been closed */
233 for (Index = 0; Index < pClient->NumPins; Index++)
234 {
235 DPRINT("Index %u Pin %p Type %x\n", Index, pClient->hPins[Index].Handle, pClient->hPins[Index].Type);
236 if (pClient->hPins[Index].Handle && pClient->hPins[Index].Type != MIXER_DEVICE_TYPE)
237 {
238 /* found an still open audio pin */
239 ZwClose(pClient->hPins[Index].Handle);
240 }
241 }
242
243 /* free pin array */
244 if (pClient->hPins)
245 ExFreePool(pClient->hPins);
246
247 /* free client context struct */
248 ExFreePool(pClient);
249
250 /* clear old client pointer */
251 IoStack->FileObject->FsContext = NULL;
252
253 /* complete request */
254 Irp->IoStatus.Status = STATUS_SUCCESS;
255 Irp->IoStatus.Information = 0;
256 IoCompleteRequest(Irp, IO_NO_INCREMENT);
257
258 /* done */
259 return STATUS_SUCCESS;
260 }
261
262 NTSTATUS
263 NTAPI
264 DriverEntry(
265 IN PDRIVER_OBJECT Driver,
266 IN PUNICODE_STRING Registry_path
267 )
268 {
269 DPRINT("Wdmaud.sys loaded\n");
270
271 Driver->DriverUnload = WdmAudUnload;
272
273 Driver->MajorFunction[IRP_MJ_CREATE] = WdmAudCreate;
274 Driver->MajorFunction[IRP_MJ_CLOSE] = WdmAudClose;
275 Driver->MajorFunction[IRP_MJ_PNP] = WdmAudPnp;
276 Driver->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp;
277 Driver->MajorFunction[IRP_MJ_CLEANUP] = WdmAudCleanup;
278 Driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = WdmAudDeviceControl;
279 Driver->MajorFunction[IRP_MJ_WRITE] = WdmAudReadWrite;
280 Driver->MajorFunction[IRP_MJ_READ] = WdmAudReadWrite;
281 Driver->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower;
282
283 return WdmAudInstallDevice(Driver);
284 }