[HAL]
[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 WaveIn %lu WaveOut %lu Mixer %lu\n", Status, WdmAudGetWaveInDeviceCount(), WdmAudGetWaveOutDeviceCount(), WdmAudGetMixerDeviceCount());
84
85 DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
86 DeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
87
88 return STATUS_SUCCESS;
89 }
90
91 VOID
92 NTAPI
93 WdmAudUnload(
94 IN PDRIVER_OBJECT driver)
95 {
96 DPRINT("WdmAudUnload called\n");
97 }
98
99 NTSTATUS
100 NTAPI
101 WdmAudPnp(
102 IN PDEVICE_OBJECT DeviceObject,
103 IN PIRP Irp)
104 {
105 PIO_STACK_LOCATION IrpStack;
106
107 DPRINT("WdmAudPnp called\n");
108
109 IrpStack = IoGetCurrentIrpStackLocation(Irp);
110
111 if (IrpStack->MinorFunction == IRP_MN_QUERY_PNP_DEVICE_STATE)
112 {
113 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
114 return KsDefaultDispatchPnp(DeviceObject, Irp);
115 }
116 return KsDefaultDispatchPnp(DeviceObject, Irp);
117 }
118
119
120 NTSTATUS
121 NTAPI
122 WdmAudCreate(
123 IN PDEVICE_OBJECT DeviceObject,
124 IN PIRP Irp)
125 {
126 NTSTATUS Status;
127 PIO_STACK_LOCATION IoStack;
128 PWDMAUD_CLIENT pClient;
129 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
130
131 /* get device extension */
132 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
133
134 #if KS_IMPLEMENTED
135 Status = KsReferenceSoftwareBusObject((KSDEVICE_HEADER)DeviceObject->DeviceExtension);
136 if (!NT_SUCCESS(Status))
137 {
138 DPRINT1("KsReferenceSoftwareBusObject failed with %x\n", Status);
139 return Status;
140 }
141 #endif
142
143 Status = WdmAudOpenSysaudio(DeviceObject, &pClient);
144 if (!NT_SUCCESS(Status))
145 {
146 DPRINT1("Failed to open sysaudio!\n");
147
148 /* complete and forget */
149 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
150 IoCompleteRequest(Irp, IO_NO_INCREMENT);
151 /* done */
152 return STATUS_UNSUCCESSFUL;
153 }
154
155 IoStack = IoGetCurrentIrpStackLocation(Irp);
156 ASSERT(IoStack->FileObject);
157
158 /* store client context in file object */
159 IoStack->FileObject->FsContext = pClient;
160 Status = STATUS_SUCCESS;
161
162 Irp->IoStatus.Status = Status;
163 Irp->IoStatus.Information = 0;
164 IoCompleteRequest(Irp, IO_NO_INCREMENT);
165
166 return Status;
167 }
168
169 NTSTATUS
170 NTAPI
171 WdmAudClose(
172 IN PDEVICE_OBJECT DeviceObject,
173 IN PIRP Irp)
174 {
175 /* nothing to do complete request */
176 #if KS_IMPLEMENTED
177 Status = KsDereferenceSoftwareBusObject(DeviceExtension->DeviceHeader);
178
179 if (NT_SUCCESS(Status))
180 {
181 if (DeviceExtension->SysAudioNotification)
182 Status = IoUnregisterPlugPlayNotification(DeviceExtension->SysAudioNotification);
183 }
184 #endif
185
186 Irp->IoStatus.Status = STATUS_SUCCESS;
187 Irp->IoStatus.Information = 0;
188 IoCompleteRequest(Irp, IO_NO_INCREMENT);
189
190 /* done */
191 return STATUS_SUCCESS;
192 }
193
194 NTSTATUS
195 NTAPI
196 WdmAudCleanup(
197 IN PDEVICE_OBJECT DeviceObject,
198 IN PIRP Irp)
199 {
200 PIO_STACK_LOCATION IoStack;
201 PWDMAUD_CLIENT pClient;
202 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
203 ULONG Index;
204 KIRQL OldIrql;
205
206 /* get device extension */
207 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
208
209 /* get current irp stack location */
210 IoStack = IoGetCurrentIrpStackLocation(Irp);
211
212 /* sanity check */
213 ASSERT(IoStack->FileObject);
214
215 /* get client context struct */
216 pClient = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
217
218 /* sanity check */
219 ASSERT(pClient);
220
221 /* acquire client context list lock */
222 KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
223
224 /* remove entry */
225 RemoveEntryList(&pClient->Entry);
226
227 /* release lock */
228 KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
229
230 /* check if all audio pins have been closed */
231 for (Index = 0; Index < pClient->NumPins; Index++)
232 {
233 DPRINT("Index %u Pin %p Type %x\n", Index, pClient->hPins[Index].Handle, pClient->hPins[Index].Type);
234 if (pClient->hPins[Index].Handle && pClient->hPins[Index].Type != MIXER_DEVICE_TYPE)
235 {
236 /* found an still open audio pin */
237 ZwClose(pClient->hPins[Index].Handle);
238 }
239 }
240
241 /* free pin array */
242 if (pClient->hPins)
243 ExFreePool(pClient->hPins);
244
245 /* free client context struct */
246 ExFreePool(pClient);
247
248 /* clear old client pointer */
249 IoStack->FileObject->FsContext = NULL;
250
251 /* complete request */
252 Irp->IoStatus.Status = STATUS_SUCCESS;
253 Irp->IoStatus.Information = 0;
254 IoCompleteRequest(Irp, IO_NO_INCREMENT);
255
256 /* done */
257 return STATUS_SUCCESS;
258 }
259
260 NTSTATUS
261 NTAPI
262 DriverEntry(
263 IN PDRIVER_OBJECT Driver,
264 IN PUNICODE_STRING Registry_path
265 )
266 {
267 DPRINT("Wdmaud.sys loaded\n");
268
269 Driver->DriverUnload = WdmAudUnload;
270
271 Driver->MajorFunction[IRP_MJ_CREATE] = WdmAudCreate;
272 Driver->MajorFunction[IRP_MJ_CLOSE] = WdmAudClose;
273 Driver->MajorFunction[IRP_MJ_PNP] = WdmAudPnp;
274 Driver->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp;
275 Driver->MajorFunction[IRP_MJ_CLEANUP] = WdmAudCleanup;
276 Driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = WdmAudDeviceControl;
277 Driver->MajorFunction[IRP_MJ_WRITE] = WdmAudReadWrite;
278 Driver->MajorFunction[IRP_MJ_READ] = WdmAudReadWrite;
279 Driver->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower;
280
281 return WdmAudInstallDevice(Driver);
282 }