- Rewrite Wave API to enumerate wave out / in devices at startup
[reactos.git] / reactos / drivers / wdm / audio / legacy / wdmaud / control.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/legacy/wdmaud/deviface.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 */
9 #include "wdmaud.h"
10
11 const GUID KSPROPSETID_Pin = {0x8C134960L, 0x51AD, 0x11CF, {0x87, 0x8A, 0x94, 0xF8, 0x01, 0xC1, 0x00, 0x00}};
12 const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
13 const GUID KSPROPSETID_Sysaudio = {0xCBE3FAA0L, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
14 const GUID KSPROPSETID_General = {0x1464EDA5L, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
15 const GUID KSINTERFACESETID_Standard = {0x1A8766A0L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
16 const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
17 const GUID KSDATAFORMAT_TYPE_AUDIO = {0x73647561L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
18 const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
19 const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
20 const GUID KSPROPSETID_Topology = {0x720D4AC0L, 0x7533, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
21
22
23 NTSTATUS
24 WdmAudControlOpen(
25 IN PDEVICE_OBJECT DeviceObject,
26 IN PIRP Irp,
27 IN PWDMAUD_DEVICE_INFO DeviceInfo,
28 IN PWDMAUD_CLIENT ClientInfo)
29 {
30 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
31 {
32 return WdmAudControlOpenMixer(DeviceObject, Irp, DeviceInfo, ClientInfo);
33 }
34
35 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
36 {
37 return WdmAudControlOpenWave(DeviceObject, Irp, DeviceInfo, ClientInfo);
38 }
39
40 return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
41 }
42
43 NTSTATUS
44 WdmAudControlDeviceType(
45 IN PDEVICE_OBJECT DeviceObject,
46 IN PIRP Irp,
47 IN PWDMAUD_DEVICE_INFO DeviceInfo,
48 IN PWDMAUD_CLIENT ClientInfo)
49 {
50 ULONG Result = 0;
51 NTSTATUS Status;
52 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
53
54 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
55
56 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
57 {
58 Result = DeviceExtension->MixerInfoCount;
59 }
60 else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
61 {
62 Result = DeviceExtension->WaveOutDeviceCount;
63 }
64 else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
65 {
66 Result = DeviceExtension->WaveInDeviceCount;
67 }
68
69 /* store result count */
70 DeviceInfo->DeviceCount = Result;
71
72 DPRINT("WdmAudControlDeviceType Status %x Devices %u\n", Status, DeviceInfo->DeviceCount);
73 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
74 }
75
76 NTSTATUS
77 WdmAudControlDeviceState(
78 IN PDEVICE_OBJECT DeviceObject,
79 IN PIRP Irp,
80 IN PWDMAUD_DEVICE_INFO DeviceInfo,
81 IN PWDMAUD_CLIENT ClientInfo)
82 {
83 KSPROPERTY Property;
84 KSSTATE State;
85 NTSTATUS Status;
86 ULONG BytesReturned;
87 PFILE_OBJECT FileObject;
88
89 //DPRINT1("WdmAudControlDeviceState\n");
90
91 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
92 if (!NT_SUCCESS(Status))
93 {
94 DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo->hDevice, DeviceInfo->DeviceType);
95 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
96 }
97
98 Property.Set = KSPROPSETID_Connection;
99 Property.Id = KSPROPERTY_CONNECTION_STATE;
100 Property.Flags = KSPROPERTY_TYPE_SET;
101
102 State = DeviceInfo->u.State;
103
104 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned);
105
106 ObDereferenceObject(FileObject);
107
108 //DPRINT1("WdmAudControlDeviceState Status %x\n", Status);
109 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
110 }
111
112 NTSTATUS
113 WdmAudCapabilities(
114 IN PDEVICE_OBJECT DeviceObject,
115 IN PIRP Irp,
116 IN PWDMAUD_DEVICE_INFO DeviceInfo,
117 IN PWDMAUD_CLIENT ClientInfo)
118 {
119 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
120 NTSTATUS Status = STATUS_UNSUCCESSFUL;
121
122 DPRINT("WdmAudCapabilities entered\n");
123
124 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
125
126 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
127 {
128 Status = WdmAudMixerCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
129 }
130 else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
131 {
132 Status = WdmAudWaveCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
133 }
134
135 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
136 }
137
138 NTSTATUS
139 NTAPI
140 WdmAudIoctlClose(
141 IN PDEVICE_OBJECT DeviceObject,
142 IN PIRP Irp,
143 IN PWDMAUD_DEVICE_INFO DeviceInfo,
144 IN PWDMAUD_CLIENT ClientInfo)
145 {
146 ULONG Index;
147
148 for(Index = 0; Index < ClientInfo->NumPins; Index++)
149 {
150 if (ClientInfo->hPins[Index].Handle == DeviceInfo->hDevice && ClientInfo->hPins[Index].Type != MIXER_DEVICE_TYPE)
151 {
152 DPRINT1("Closing device %p\n", DeviceInfo->hDevice);
153 ZwClose(DeviceInfo->hDevice);
154 ClientInfo->hPins[Index].Handle = NULL;
155 SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
156 return STATUS_SUCCESS;
157 }
158 }
159
160 SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO));
161 return STATUS_INVALID_PARAMETER;
162 }
163
164 NTSTATUS
165 NTAPI
166 WdmAudFrameSize(
167 IN PDEVICE_OBJECT DeviceObject,
168 IN PIRP Irp,
169 IN PWDMAUD_DEVICE_INFO DeviceInfo,
170 IN PWDMAUD_CLIENT ClientInfo)
171 {
172 PFILE_OBJECT FileObject;
173 KSPROPERTY Property;
174 ULONG BytesReturned;
175 KSALLOCATOR_FRAMING Framing;
176 NTSTATUS Status;
177
178 /* Get sysaudio pin file object */
179 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
180 if (!NT_SUCCESS(Status))
181 {
182 DPRINT1("Invalid buffer handle %x\n", DeviceInfo->hDevice);
183 return SetIrpIoStatus(Irp, Status, 0);
184 }
185
186 /* Setup get framing request */
187 Property.Id = KSPROPERTY_CONNECTION_ALLOCATORFRAMING;
188 Property.Flags = KSPROPERTY_TYPE_GET;
189 Property.Set = KSPROPSETID_Connection;
190
191 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Framing, sizeof(KSALLOCATOR_FRAMING), &BytesReturned);
192 /* Did we succeed */
193 if (NT_SUCCESS(Status))
194 {
195 /* Store framesize */
196 DeviceInfo->u.FrameSize = Framing.FrameSize;
197 }
198
199 /* Release file object */
200 ObDereferenceObject(FileObject);
201
202 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
203
204 }
205
206
207 NTSTATUS
208 NTAPI
209 WdmAudDeviceControl(
210 IN PDEVICE_OBJECT DeviceObject,
211 IN PIRP Irp)
212 {
213 PIO_STACK_LOCATION IoStack;
214 PWDMAUD_DEVICE_INFO DeviceInfo;
215 PWDMAUD_CLIENT ClientInfo;
216
217 IoStack = IoGetCurrentIrpStackLocation(Irp);
218
219 DPRINT("WdmAudDeviceControl entered\n");
220
221 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(WDMAUD_DEVICE_INFO))
222 {
223 /* invalid parameter */
224 DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(WDMAUD_DEVICE_INFO));
225 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
226 }
227
228 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer;
229
230 if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE)
231 {
232 /* invalid parameter */
233 DPRINT1("Error: device type not set\n");
234 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
235 }
236
237 if (!IoStack->FileObject)
238 {
239 /* file object parameter */
240 DPRINT1("Error: file object is not attached\n");
241 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
242 }
243 ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
244
245 DPRINT("WdmAudDeviceControl entered\n");
246
247 switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
248 {
249 case IOCTL_OPEN_WDMAUD:
250 return WdmAudControlOpen(DeviceObject, Irp, DeviceInfo, ClientInfo);
251 case IOCTL_GETNUMDEVS_TYPE:
252 return WdmAudControlDeviceType(DeviceObject, Irp, DeviceInfo, ClientInfo);
253 case IOCTL_SETDEVICE_STATE:
254 return WdmAudControlDeviceState(DeviceObject, Irp, DeviceInfo, ClientInfo);
255 case IOCTL_GETCAPABILITIES:
256 return WdmAudCapabilities(DeviceObject, Irp, DeviceInfo, ClientInfo);
257 case IOCTL_CLOSE_WDMAUD:
258 return WdmAudIoctlClose(DeviceObject, Irp, DeviceInfo, ClientInfo);
259 case IOCTL_GETFRAMESIZE:
260 return WdmAudFrameSize(DeviceObject, Irp, DeviceInfo, ClientInfo);
261 case IOCTL_GETLINEINFO:
262 return WdmAudGetLineInfo(DeviceObject, Irp, DeviceInfo, ClientInfo);
263 case IOCTL_GETLINECONTROLS:
264 return WdmAudGetLineControls(DeviceObject, Irp, DeviceInfo, ClientInfo);
265 case IOCTL_SETCONTROLDETAILS:
266 return WdmAudSetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo);
267 case IOCTL_GETCONTROLDETAILS:
268 return WdmAudGetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo);
269
270 case IOCTL_GETPOS:
271 case IOCTL_GETDEVID:
272 case IOCTL_GETVOLUME:
273 case IOCTL_SETVOLUME:
274
275 DPRINT1("Unhandeled %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
276 break;
277 }
278
279 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
280 }
281
282 NTSTATUS
283 NTAPI
284 WdmAudWriteCompletion(
285 IN PDEVICE_OBJECT DeviceObject,
286 IN PIRP LowerIrp,
287 IN PVOID Context)
288 {
289 //PIRP Irp;
290 ASSERT(LowerIrp->PendingReturned == FALSE);
291 /* get original irp */
292 //Irp = (PIRP)Context;
293
294 /* save status */
295 //Irp->IoStatus.Status = LowerIrp->IoStatus.Status;
296 //Irp->IoStatus.Information = LowerIrp->IoStatus.Information;
297 /* complete request */
298 //IoCompleteRequest(Irp, IO_SOUND_INCREMENT);
299 /* return success to free irp */
300 return STATUS_SUCCESS;
301 }
302
303
304 NTSTATUS
305 NTAPI
306 WdmAudWrite(
307 IN PDEVICE_OBJECT DeviceObject,
308 IN PIRP Irp)
309 {
310 PIO_STACK_LOCATION IoStack;
311 PWDMAUD_DEVICE_INFO DeviceInfo;
312 PWDMAUD_CLIENT ClientInfo;
313 NTSTATUS Status = STATUS_SUCCESS;
314 PUCHAR Buffer;
315 PFILE_OBJECT FileObject;
316 PMDL Mdl;
317 //PIRP LowerIrp;
318 PCONTEXT_WRITE Packet;
319 PVOID SystemBuffer;
320 //LARGE_INTEGER Offset;
321 IO_STATUS_BLOCK IoStatusBlock;
322
323 IoStack = IoGetCurrentIrpStackLocation(Irp);
324
325 //DPRINT("WdmAudWrite entered\n");
326
327 if (IoStack->Parameters.Write.Length < sizeof(WDMAUD_DEVICE_INFO))
328 {
329 /* invalid parameter */
330 DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.Write.Length, sizeof(WDMAUD_DEVICE_INFO));
331 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
332 }
333
334 DeviceInfo = (PWDMAUD_DEVICE_INFO)MmGetMdlVirtualAddress(Irp->MdlAddress);
335
336
337 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
338 if (!NT_SUCCESS(Status))
339 {
340 DPRINT1("Invalid buffer handle %x\n", DeviceInfo->hDevice);
341 return SetIrpIoStatus(Irp, Status, 0);
342 }
343
344
345 //DPRINT("DeviceInfo %p %p %p\n", DeviceInfo, Irp->MdlAddress->StartVa, Irp->MdlAddress->MappedSystemVa);
346 if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE)
347 {
348 /* invalid parameter */
349 DPRINT1("Error: device type not set\n");
350 ObDereferenceObject(FileObject);
351 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
352 }
353
354 if (!IoStack->FileObject)
355 {
356 /* file object parameter */
357 DPRINT1("Error: file object is not attached\n");
358 ObDereferenceObject(FileObject);
359 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
360 }
361 ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
362
363
364 /* setup stream context */
365 Packet = (PCONTEXT_WRITE)ExAllocatePool(NonPagedPool, sizeof(CONTEXT_WRITE));
366 if (!Packet)
367 {
368 /* no memory */
369 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
370 }
371
372 Packet->Header.FrameExtent = DeviceInfo->Header.FrameExtent;
373 Packet->Header.DataUsed = DeviceInfo->Header.DataUsed;
374 Packet->Header.Size = sizeof(KSSTREAM_HEADER);
375 Packet->Header.PresentationTime.Numerator = 1;
376 Packet->Header.PresentationTime.Denominator = 1;
377 Packet->Irp = Irp;
378
379 Buffer = ExAllocatePool(NonPagedPool, DeviceInfo->Header.DataUsed);
380 if (!Buffer)
381 {
382 /* no memory */
383 ExFreePool(Packet);
384 ObDereferenceObject(FileObject);
385 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
386 }
387 Packet->Header.Data = Buffer;
388
389 Mdl = IoAllocateMdl(DeviceInfo->Header.Data, DeviceInfo->Header.DataUsed, FALSE, FALSE, FALSE);
390 if (!Mdl)
391 {
392 /* no memory */
393 ExFreePool(Packet);
394 ObDereferenceObject(FileObject);
395 ExFreePool(Buffer);
396 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
397 }
398
399 _SEH2_TRY
400 {
401 MmProbeAndLockPages(Mdl, UserMode, IoReadAccess);
402 }
403 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
404 {
405 /* Exception, get the error code */
406 Status = _SEH2_GetExceptionCode();
407 }
408 _SEH2_END;
409
410 if (!NT_SUCCESS(Status))
411 {
412 DPRINT1("Invalid buffer supplied\n");
413 ExFreePool(Buffer);
414 ExFreePool(Packet);
415 IoFreeMdl(Mdl);
416 ObDereferenceObject(FileObject);
417 return SetIrpIoStatus(Irp, Status, 0);
418 }
419
420 SystemBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority );
421 if (!SystemBuffer)
422 {
423 DPRINT1("Invalid buffer supplied\n");
424 ExFreePool(Buffer);
425 ExFreePool(Packet);
426 IoFreeMdl(Mdl);
427 ObDereferenceObject(FileObject);
428 return SetIrpIoStatus(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
429 }
430
431 RtlMoveMemory(Buffer, SystemBuffer, DeviceInfo->Header.DataUsed);
432 MmUnlockPages(Mdl);
433 IoFreeMdl(Mdl);
434
435 #if 1
436 KsStreamIo(FileObject, NULL, NULL, NULL, NULL, 0, &IoStatusBlock, Packet, sizeof(CONTEXT_WRITE), KSSTREAM_WRITE, UserMode);
437 /* dereference file object */
438 ObDereferenceObject(FileObject);
439 return IoStatusBlock.Status;
440 #else
441 Offset.QuadPart = 0L;
442
443 /* now build the irp */
444 LowerIrp = IoBuildAsynchronousFsdRequest (IRP_MJ_WRITE,
445 IoGetRelatedDeviceObject(FileObject),
446 Packet,
447 sizeof(KSSTREAM_HEADER),
448 &Offset,
449 NULL);
450
451 if (!LowerIrp)
452 {
453 /* failed to create an associated irp */
454 ExFreePool(Buffer);
455 ExFreePool(Packet);
456 ObDereferenceObject(FileObject);
457
458 return SetIrpIoStatus(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
459 }
460
461 /* get next stack location */
462 IoStack = IoGetNextIrpStackLocation(LowerIrp);
463
464 /* attach file object */
465 IoStack->FileObject = FileObject;
466
467 /* set a completion routine */
468 IoSetCompletionRoutine(LowerIrp, WdmAudWriteCompletion, (PVOID)Irp, TRUE, TRUE, TRUE);
469
470 /* mark irp as pending */
471 //IoMarkIrpPending(Irp);
472 Irp->IoStatus.Information = DeviceInfo->BufferSize;
473 Irp->IoStatus.Status = STATUS_SUCCESS;
474 IoCompleteRequest(Irp, IO_NO_INCREMENT);
475 DPRINT1("Wrote %u\n", DeviceInfo->BufferSize);
476 /* call the driver */
477 Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), LowerIrp);
478
479 /* dereference file object */
480 ObDereferenceObject(FileObject);
481
482 return STATUS_SUCCESS;
483 #endif
484 }