- Disable message flood when playing audio files as it is very time critical and...
[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
21 NTSTATUS
22 SetIrpIoStatus(
23 IN PIRP Irp,
24 IN NTSTATUS Status,
25 IN ULONG Length)
26 {
27 Irp->IoStatus.Information = Length;
28 Irp->IoStatus.Status = Status;
29 IoCompleteRequest(Irp, IO_NO_INCREMENT);
30 return Status;
31
32 }
33
34 NTSTATUS
35 GetFilterIdAndPinId(
36 IN PDEVICE_OBJECT DeviceObject,
37 IN PWDMAUD_DEVICE_INFO DeviceInfo,
38 IN PWDMAUD_CLIENT ClientInfo,
39 IN PULONG FilterId,
40 IN PULONG PinId)
41 {
42 KSP_PIN Pin;
43 ULONG Count, BytesReturned, Index, SubIndex, Result, NumPins;
44 NTSTATUS Status;
45 KSPIN_COMMUNICATION Communication;
46 KSPIN_DATAFLOW DataFlow;
47
48 if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceInfo->DeviceType != WAVE_IN_DEVICE_TYPE)
49 {
50 DPRINT1("FIXME: Unsupported device type %x\n", DeviceInfo->DeviceType);
51 return STATUS_UNSUCCESSFUL;
52 }
53
54 Pin.Property.Set = KSPROPSETID_Sysaudio;
55 Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
56 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
57
58 Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
59 if (!NT_SUCCESS(Status))
60 return STATUS_UNSUCCESSFUL;
61
62 Result = 0;
63 for(Index = 0; Index < Count; Index++)
64 {
65 /* query number of pins */
66 Pin.Reserved = Index; // see sysaudio
67 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
68 Pin.Property.Set = KSPROPSETID_Pin;
69 Pin.Property.Id = KSPROPERTY_PIN_CTYPES;
70 Pin.PinId = 0;
71
72 Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
73 if (NT_SUCCESS(Status))
74 {
75 /* enumerate now all pins */
76 for(SubIndex = 0; SubIndex < NumPins; SubIndex++)
77 {
78 Pin.PinId = SubIndex;
79 Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
80 Communication = KSPIN_COMMUNICATION_NONE;
81
82 /* get pin communication type */
83 KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
84
85 Pin.Property.Id = KSPROPERTY_PIN_DATAFLOW;
86 DataFlow = 0;
87
88 /* get pin dataflow type */
89 KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
90
91 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
92 {
93 if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
94 {
95 if(DeviceInfo->DeviceIndex == Result)
96 {
97 /* found the index */
98 *FilterId = Index;
99 *PinId = SubIndex;
100 return STATUS_SUCCESS;
101 }
102
103 Result++;
104 }
105 }
106 else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
107 {
108 if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
109 {
110 if(DeviceInfo->DeviceIndex == Result)
111 {
112 /* found the index */
113 *FilterId = Index;
114 *PinId = SubIndex;
115 return STATUS_SUCCESS;
116 }
117 Result++;
118 }
119 }
120 }
121 }
122 }
123
124 return STATUS_UNSUCCESSFUL;
125 }
126
127 NTSTATUS
128 WdmAudControlOpen(
129 IN PDEVICE_OBJECT DeviceObject,
130 IN PIRP Irp,
131 IN PWDMAUD_DEVICE_INFO DeviceInfo,
132 IN PWDMAUD_CLIENT ClientInfo)
133 {
134 PSYSAUDIO_INSTANCE_INFO InstanceInfo;
135 ULONG BytesReturned;
136 NTSTATUS Status;
137 ACCESS_MASK DesiredAccess = 0;
138 HANDLE PinHandle;
139 KSPIN_CONNECT * PinConnect;
140 ULONG Length;
141 KSDATAFORMAT_WAVEFORMATEX * DataFormat;
142 ULONG FilterId;
143 ULONG PinId;
144
145 if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceInfo->DeviceType != WAVE_IN_DEVICE_TYPE)
146 {
147 DPRINT1("FIXME: only waveout devices are supported\n");
148 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
149 }
150
151 Status = GetFilterIdAndPinId(DeviceObject, DeviceInfo, ClientInfo, &FilterId, &PinId);
152 if (!NT_SUCCESS(Status))
153 {
154 DPRINT1("Invalid device index %u\n", DeviceInfo->DeviceIndex);
155 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
156 }
157
158
159 Length = sizeof(KSDATAFORMAT_WAVEFORMATEX) + sizeof(KSPIN_CONNECT) + sizeof(SYSAUDIO_INSTANCE_INFO);
160 InstanceInfo = ExAllocatePool(NonPagedPool, Length);
161 if (!InstanceInfo)
162 {
163 /* no memory */
164 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
165 }
166
167 InstanceInfo->Property.Set = KSPROPSETID_Sysaudio;
168 InstanceInfo->Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
169 InstanceInfo->Property.Flags = KSPROPERTY_TYPE_SET;
170 InstanceInfo->Flags = 0;
171 InstanceInfo->DeviceNumber = FilterId;
172
173 Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
174
175 if (!NT_SUCCESS(Status))
176 {
177 /* failed to acquire audio device */
178 DPRINT1("KsSynchronousIoControlDevice failed with %x\n", Status);
179 ExFreePool(InstanceInfo);
180 return SetIrpIoStatus(Irp, Status, 0);
181 }
182
183 if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE ||
184 DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE ||
185 DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
186 {
187 DesiredAccess |= GENERIC_READ;
188 }
189
190 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE ||
191 DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE ||
192 DeviceInfo->DeviceType == AUX_DEVICE_TYPE ||
193 DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
194 {
195 DesiredAccess |= GENERIC_WRITE;
196 }
197
198 PinConnect = (KSPIN_CONNECT*)(InstanceInfo + 1);
199
200
201 PinConnect->Interface.Set = KSINTERFACESETID_Standard;
202 PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
203 PinConnect->Interface.Flags = 0;
204 PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
205 PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
206 PinConnect->Medium.Flags = 0;
207 PinConnect->PinId = PinId;
208 PinConnect->PinToHandle = ClientInfo->hSysAudio;
209 PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
210 PinConnect->Priority.PrioritySubClass = 1;
211
212
213 DataFormat = (KSDATAFORMAT_WAVEFORMATEX*) (PinConnect + 1);
214 DataFormat->WaveFormatEx.wFormatTag = DeviceInfo->u.WaveFormatEx.wFormatTag;
215 DataFormat->WaveFormatEx.nChannels = DeviceInfo->u.WaveFormatEx.nChannels;
216 DataFormat->WaveFormatEx.nSamplesPerSec = DeviceInfo->u.WaveFormatEx.nSamplesPerSec;
217 DataFormat->WaveFormatEx.nBlockAlign = DeviceInfo->u.WaveFormatEx.nBlockAlign;
218 DataFormat->WaveFormatEx.nAvgBytesPerSec = DeviceInfo->u.WaveFormatEx.nAvgBytesPerSec;
219 DataFormat->WaveFormatEx.wBitsPerSample = DeviceInfo->u.WaveFormatEx.wBitsPerSample;
220 DataFormat->WaveFormatEx.cbSize = 0;
221 DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
222 DataFormat->DataFormat.Flags = 0;
223 DataFormat->DataFormat.Reserved = 0;
224 DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
225
226 if (DeviceInfo->u.WaveFormatEx.wFormatTag != WAVE_FORMAT_PCM)
227 DPRINT1("FIXME\n");
228
229 DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
230 DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
231 DataFormat->DataFormat.SampleSize = 4;
232
233 /* ros specific pin creation request */
234 InstanceInfo->Property.Id = (ULONG)-1;
235 Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)InstanceInfo, Length, &PinHandle, sizeof(HANDLE), &BytesReturned);
236 if (NT_SUCCESS(Status))
237 {
238 PHANDLE Handels = ExAllocatePool(NonPagedPool, sizeof(HANDLE) * (ClientInfo->NumPins+1));
239
240 if (Handels)
241 {
242 if (ClientInfo->NumPins)
243 {
244 RtlMoveMemory(Handels, ClientInfo->hPins, sizeof(HANDLE) * ClientInfo->NumPins);
245 ExFreePool(ClientInfo->hPins);
246 }
247
248 ClientInfo->hPins = Handels;
249 ClientInfo->hPins[ClientInfo->NumPins] = PinHandle;
250 ClientInfo->NumPins++;
251 }
252 DeviceInfo->hDevice = PinHandle;
253 }
254 else
255 {
256 DeviceInfo->hDevice = NULL;
257 }
258
259 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
260 }
261
262 NTSTATUS
263 WdmAudControlDeviceType(
264 IN PDEVICE_OBJECT DeviceObject,
265 IN PIRP Irp,
266 IN PWDMAUD_DEVICE_INFO DeviceInfo,
267 IN PWDMAUD_CLIENT ClientInfo)
268 {
269 KSP_PIN Pin;
270 ULONG Count, BytesReturned, Index, SubIndex, Result, NumPins;
271 NTSTATUS Status;
272 KSPIN_COMMUNICATION Communication;
273 KSPIN_DATAFLOW DataFlow;
274
275 if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceInfo->DeviceType != WAVE_IN_DEVICE_TYPE)
276 {
277 DPRINT1("FIXME: Unsupported device type %x\n", DeviceInfo->DeviceType);
278 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
279 }
280
281 Pin.Property.Set = KSPROPSETID_Sysaudio;
282 Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
283 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
284
285 Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
286 if (!NT_SUCCESS(Status))
287 {
288 DPRINT1("KSPROPERTY_SYSAUDIO_DEVICE_COUNT failed with %x\n", Status);
289 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
290 }
291 Result = 0;
292 /* now enumerate all available filters */
293 for(Index = 0; Index < Count; Index++)
294 {
295 /* query number of pins */
296 Pin.Reserved = Index; // see sysaudio
297 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
298 Pin.Property.Set = KSPROPSETID_Pin;
299 Pin.Property.Id = KSPROPERTY_PIN_CTYPES;
300 Pin.PinId = 0;
301
302 Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
303 if (NT_SUCCESS(Status))
304 {
305 /* enumerate now all pins */
306 for(SubIndex = 0; SubIndex < NumPins; SubIndex++)
307 {
308 Pin.PinId = SubIndex;
309 Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
310 Communication = KSPIN_COMMUNICATION_NONE;
311
312 /* get pin communication type */
313 KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
314
315 Pin.Property.Id = KSPROPERTY_PIN_DATAFLOW;
316 DataFlow = 0;
317
318 /* get pin dataflow type */
319 KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
320
321 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
322 {
323 if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
324 Result++;
325 }
326 else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
327 {
328 if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
329 Result++;
330 }
331 }
332 }
333 else
334 DPRINT1("KSPROPERTY_PIN_CTYPES index %u failed with %x\n", Index, Status);
335 }
336
337
338 if (NT_SUCCESS(Status))
339 DeviceInfo->DeviceCount = Result;
340 else
341 DeviceInfo->DeviceCount = 0;
342
343 DPRINT1("WdmAudControlDeviceType Status %x Devices %u\n", Status, DeviceInfo->DeviceCount);
344 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
345 }
346
347 NTSTATUS
348 WdmAudControlDeviceState(
349 IN PDEVICE_OBJECT DeviceObject,
350 IN PIRP Irp,
351 IN PWDMAUD_DEVICE_INFO DeviceInfo,
352 IN PWDMAUD_CLIENT ClientInfo)
353 {
354 KSPROPERTY Property;
355 KSSTATE State;
356 NTSTATUS Status;
357 ULONG BytesReturned;
358 PFILE_OBJECT FileObject;
359
360 DPRINT1("WdmAudControlDeviceState\n");
361
362 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
363 if (!NT_SUCCESS(Status))
364 {
365 DPRINT1("Error: invalid device handle provided %p\n", DeviceInfo->hDevice);
366 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
367 }
368
369 Property.Set = KSPROPSETID_Connection;
370 Property.Id = KSPROPERTY_CONNECTION_STATE;
371 Property.Flags = KSPROPERTY_TYPE_SET;
372
373 State = DeviceInfo->State;
374
375 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned);
376
377 ObDereferenceObject(FileObject);
378
379 DPRINT1("WdmAudControlDeviceState Status %x\n", Status);
380 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
381 }
382
383 NTSTATUS
384 NTAPI
385 WdmAudWriteCompleted(
386 IN PDEVICE_OBJECT DeviceObject,
387 IN PIRP Irp,
388 IN PVOID Ctx)
389 {
390 PWRITE_CONTEXT Context = (PWRITE_CONTEXT)Ctx;
391
392 Context->Irp->IoStatus.Information = Context->Length;
393 Context->Irp->IoStatus.Status = Irp->IoStatus.Status;
394 IoCompleteRequest(Context->Irp, IO_SOUND_INCREMENT);
395
396 ExFreePool(Context);
397 return STATUS_SUCCESS;
398 }
399
400 ULONG
401 CheckFormatSupport(
402 IN PKSDATARANGE_AUDIO DataRangeAudio,
403 ULONG SampleFrequency,
404 ULONG Mono8Bit,
405 ULONG Stereo8Bit,
406 ULONG Mono16Bit,
407 ULONG Stereo16Bit)
408 {
409 ULONG Result = 0;
410
411 if (DataRangeAudio->MinimumSampleFrequency <= SampleFrequency && DataRangeAudio->MaximumSampleFrequency >= SampleFrequency)
412 {
413 if (DataRangeAudio->MinimumBitsPerSample <= 8 && DataRangeAudio->MaximumBitsPerSample >= 8)
414 {
415 Result |= Mono8Bit;
416 if (DataRangeAudio->MaximumChannels >= 2)
417 {
418 Result |= Stereo8Bit;
419 }
420 }
421
422 if (DataRangeAudio->MinimumBitsPerSample <= 16 && DataRangeAudio->MaximumBitsPerSample >= 16)
423 {
424 Result |= Mono16Bit;
425 if (DataRangeAudio->MaximumChannels >= 2)
426 {
427 Result |= Stereo8Bit;
428 }
429 }
430 }
431 return Result;
432
433 }
434
435 NTSTATUS
436 WdmAudCapabilities(
437 IN PDEVICE_OBJECT DeviceObject,
438 IN PIRP Irp,
439 IN PWDMAUD_DEVICE_INFO DeviceInfo,
440 IN PWDMAUD_CLIENT ClientInfo)
441 {
442 NTSTATUS Status = STATUS_UNSUCCESSFUL;
443 KSP_PIN PinProperty;
444 KSCOMPONENTID ComponentId;
445 KSMULTIPLE_ITEM * MultipleItem;
446 ULONG BytesReturned;
447 PKSDATARANGE_AUDIO DataRangeAudio;
448 PKSDATARANGE DataRange;
449 ULONG Index;
450 ULONG wChannels = 0;
451 ULONG dwFormats = 0;
452 ULONG dwSupport = 0;
453 ULONG FilterId;
454 ULONG PinId;
455
456 DPRINT("WdmAudCapabilities entered\n");
457
458
459 Status = GetFilterIdAndPinId(DeviceObject, DeviceInfo, ClientInfo, &FilterId, &PinId);
460 if (!NT_SUCCESS(Status))
461 {
462 DPRINT1("Invalid device index provided %u\n", DeviceInfo->DeviceIndex);
463 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
464 }
465
466 PinProperty.PinId = FilterId;
467 PinProperty.Property.Set = KSPROPSETID_Sysaudio;
468 PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_COMPONENT_ID;
469 PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
470
471 RtlZeroMemory(&ComponentId, sizeof(KSCOMPONENTID));
472
473 Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)&ComponentId, sizeof(KSCOMPONENTID), &BytesReturned);
474 if (NT_SUCCESS(Status))
475 {
476 DeviceInfo->u.WaveOutCaps.wMid = ComponentId.Manufacturer.Data1 - 0xd5a47fa7;
477 DeviceInfo->u.WaveOutCaps.vDriverVersion = MAKELONG(ComponentId.Version, ComponentId.Revision);
478 }
479
480 PinProperty.Reserved = DeviceInfo->DeviceIndex;
481 PinProperty.PinId = PinId;
482 PinProperty.Property.Set = KSPROPSETID_Pin;
483 PinProperty.Property.Id = KSPROPERTY_PIN_DATARANGES;
484 PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
485
486 BytesReturned = 0;
487 Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)NULL, 0, &BytesReturned);
488 if (Status != STATUS_BUFFER_TOO_SMALL)
489 {
490 return SetIrpIoStatus(Irp, Status, 0);
491 }
492
493 MultipleItem = ExAllocatePool(NonPagedPool, BytesReturned);
494 if (!MultipleItem)
495 {
496 /* no memory */
497 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
498 }
499
500 Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
501 if (!NT_SUCCESS(Status))
502 {
503 ExFreePool(MultipleItem);
504 return SetIrpIoStatus(Irp, Status, 0);
505 }
506
507 DataRange = (PKSDATARANGE) (MultipleItem + 1);
508 for(Index = 0; Index < MultipleItem->Count; Index++)
509 {
510 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
511 {
512 if (DataRange->FormatSize == sizeof(KSDATARANGE_AUDIO))
513 {
514 DataRangeAudio = (PKSDATARANGE_AUDIO)DataRange;
515
516 if (IsEqualGUIDAligned(&DataRangeAudio->DataRange.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
517 IsEqualGUIDAligned(&DataRangeAudio->DataRange.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
518 IsEqualGUIDAligned(&DataRangeAudio->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
519 {
520 DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio->MinimumSampleFrequency, DataRangeAudio->MaximumSampleFrequency,
521 DataRangeAudio->MinimumBitsPerSample, DataRangeAudio->MaximumBitsPerSample, DataRangeAudio->MaximumChannels);
522
523 dwFormats |= CheckFormatSupport(DataRangeAudio, 11025, WAVE_FORMAT_1M08, WAVE_FORMAT_1S08, WAVE_FORMAT_1M16, WAVE_FORMAT_1S16);
524 dwFormats |= CheckFormatSupport(DataRangeAudio, 22050, WAVE_FORMAT_2M08, WAVE_FORMAT_2S08, WAVE_FORMAT_2M16, WAVE_FORMAT_2S16);
525 dwFormats |= CheckFormatSupport(DataRangeAudio, 44100, WAVE_FORMAT_4M08, WAVE_FORMAT_4S08, WAVE_FORMAT_4M16, WAVE_FORMAT_4S16);
526 dwFormats |= CheckFormatSupport(DataRangeAudio, 48000, WAVE_FORMAT_48M08, WAVE_FORMAT_48S08, WAVE_FORMAT_48M16, WAVE_FORMAT_48S16);
527 dwFormats |= CheckFormatSupport(DataRangeAudio, 96000, WAVE_FORMAT_96M08, WAVE_FORMAT_96S08, WAVE_FORMAT_96M16, WAVE_FORMAT_96S16);
528
529
530 wChannels = DataRangeAudio->MaximumChannels;
531 dwSupport = WAVECAPS_VOLUME; //FIXME get info from nodes
532 }
533 }
534 }
535 DataRange = (PKSDATARANGE)((PUCHAR)DataRange + DataRange->FormatSize);
536 }
537
538 DeviceInfo->u.WaveOutCaps.dwFormats = dwFormats;
539 DeviceInfo->u.WaveOutCaps.dwSupport = dwSupport;
540 DeviceInfo->u.WaveOutCaps.wChannels = wChannels;
541 DeviceInfo->u.WaveOutCaps.szPname[0] = L'\0';
542
543
544 ExFreePool(MultipleItem);
545 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
546 }
547
548 NTSTATUS
549 NTAPI
550 WdmAudClose(
551 IN PDEVICE_OBJECT DeviceObject,
552 IN PIRP Irp,
553 IN PWDMAUD_DEVICE_INFO DeviceInfo,
554 IN PWDMAUD_CLIENT ClientInfo)
555 {
556 ULONG Index;
557
558 for(Index = 0; Index < ClientInfo->NumPins; Index++)
559 {
560 if (ClientInfo->hPins[Index] == DeviceInfo->hDevice)
561 {
562 DPRINT1("Closing device %p\n", DeviceInfo->hDevice);
563 ZwClose(DeviceInfo->hDevice);
564 ClientInfo->hPins[Index] = NULL;
565 SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
566 return STATUS_SUCCESS;
567 }
568 }
569 SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO));
570 return STATUS_INVALID_PARAMETER;
571 }
572
573 NTSTATUS
574 NTAPI
575 WdmAudDeviceControl(
576 IN PDEVICE_OBJECT DeviceObject,
577 IN PIRP Irp)
578 {
579 PIO_STACK_LOCATION IoStack;
580 PWDMAUD_DEVICE_INFO DeviceInfo;
581 PWDMAUD_CLIENT ClientInfo;
582
583 IoStack = IoGetCurrentIrpStackLocation(Irp);
584
585 DPRINT1("WdmAudDeviceControl entered\n");
586
587 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(WDMAUD_DEVICE_INFO))
588 {
589 /* invalid parameter */
590 DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(WDMAUD_DEVICE_INFO));
591 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
592 }
593
594 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer;
595
596 if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE)
597 {
598 /* invalid parameter */
599 DPRINT1("Error: device type not set\n");
600 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
601 }
602
603 if (!IoStack->FileObject)
604 {
605 /* file object parameter */
606 DPRINT1("Error: file object is not attached\n");
607 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
608 }
609 ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
610
611 DPRINT1("WdmAudDeviceControl entered\n");
612
613 switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
614 {
615 case IOCTL_OPEN_WDMAUD:
616 return WdmAudControlOpen(DeviceObject, Irp, DeviceInfo, ClientInfo);
617 case IOCTL_GETNUMDEVS_TYPE:
618 return WdmAudControlDeviceType(DeviceObject, Irp, DeviceInfo, ClientInfo);
619 case IOCTL_SETDEVICE_STATE:
620 return WdmAudControlDeviceState(DeviceObject, Irp, DeviceInfo, ClientInfo);
621 case IOCTL_GETCAPABILITIES:
622 return WdmAudCapabilities(DeviceObject, Irp, DeviceInfo, ClientInfo);
623 case IOCTL_CLOSE_WDMAUD:
624 return WdmAudClose(DeviceObject, Irp, DeviceInfo, ClientInfo);
625 case IOCTL_GETDEVID:
626 case IOCTL_GETVOLUME:
627 case IOCTL_SETVOLUME:
628
629 DPRINT1("Unhandeled %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
630 break;
631 }
632
633 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
634 }
635
636 NTSTATUS
637 NTAPI
638 WdmAudWrite(
639 IN PDEVICE_OBJECT DeviceObject,
640 IN PIRP Irp)
641 {
642 PIO_STACK_LOCATION IoStack;
643 PWDMAUD_DEVICE_INFO DeviceInfo;
644 PWDMAUD_CLIENT ClientInfo;
645 NTSTATUS Status = STATUS_SUCCESS;
646 PUCHAR Buffer;
647 PCONTEXT_WRITE Packet;
648 PFILE_OBJECT FileObject;
649 IO_STATUS_BLOCK IoStatusBlock;
650
651 IoStack = IoGetCurrentIrpStackLocation(Irp);
652
653 //DPRINT("WdmAudWrite entered\n");
654
655 if (IoStack->Parameters.Write.Length < sizeof(WDMAUD_DEVICE_INFO))
656 {
657 /* invalid parameter */
658 DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.Write.Length, sizeof(WDMAUD_DEVICE_INFO));
659 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
660 }
661
662 DeviceInfo = (PWDMAUD_DEVICE_INFO)MmGetMdlVirtualAddress(Irp->MdlAddress);
663
664
665 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
666 if (!NT_SUCCESS(Status))
667 {
668 DPRINT1("Invalid buffer handle %x\n", DeviceInfo->hDevice);
669 return SetIrpIoStatus(Irp, Status, 0);
670 }
671
672
673 //DPRINT("DeviceInfo %p %p %p\n", DeviceInfo, Irp->MdlAddress->StartVa, Irp->MdlAddress->MappedSystemVa);
674 if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE)
675 {
676 /* invalid parameter */
677 DPRINT1("Error: device type not set\n");
678 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
679 }
680
681 if (!IoStack->FileObject)
682 {
683 /* file object parameter */
684 DPRINT1("Error: file object is not attached\n");
685 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
686 }
687 ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
688
689
690 /* setup stream context */
691 Packet = (PCONTEXT_WRITE)ExAllocatePool(NonPagedPool, sizeof(CONTEXT_WRITE));
692 if (!Packet)
693 {
694 /* no memory */
695 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
696 }
697
698 Packet->Header.FrameExtent = DeviceInfo->BufferSize;
699 Packet->Header.DataUsed = DeviceInfo->BufferSize;
700 Packet->Header.Size = sizeof(KSSTREAM_HEADER);
701 Packet->Header.PresentationTime.Numerator = 1;
702 Packet->Header.PresentationTime.Denominator = 1;
703 Packet->Irp = Irp;
704
705 Buffer = ExAllocatePool(NonPagedPool, DeviceInfo->BufferSize);
706 if (!Buffer)
707 {
708 /* no memory */
709 ExFreePool(Packet);
710 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
711 }
712 Packet->Header.Data = Buffer;
713
714 _SEH2_TRY
715 {
716 ProbeForRead(DeviceInfo->Buffer, DeviceInfo->BufferSize, TYPE_ALIGNMENT(char));
717 RtlMoveMemory(Buffer, DeviceInfo->Buffer, DeviceInfo->BufferSize);
718 }
719 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
720 {
721 /* Exception, get the error code */
722 Status = _SEH2_GetExceptionCode();
723 }
724 _SEH2_END;
725
726 if (!NT_SUCCESS(Status))
727 {
728 DPRINT1("Invalid buffer supplied\n");
729 ExFreePool(Buffer);
730 ExFreePool(Packet);
731 return SetIrpIoStatus(Irp, Status, 0);
732 }
733
734 KsStreamIo(FileObject, NULL, NULL, NULL, NULL, 0, &IoStatusBlock, Packet, sizeof(CONTEXT_WRITE), KSSTREAM_WRITE, KernelMode);
735
736
737 return IoStatusBlock.Status;
738 }
739