be57468d2ad68462e277bb97b582154abfc889ae
[reactos.git] / reactos / drivers / wdm / audio / legacy / wdmaud / wave.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/legacy/wdmaud/wave.c
5 * PURPOSE: Wave Out enumeration
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 */
9 #include "wdmaud.h"
10
11
12 typedef struct
13 {
14 ULONG SampleRate;
15 ULONG Bit8Mono;
16 ULONG Bit8Stereo;
17 ULONG Bit16Mono;
18 ULONG Bit16Stereo;
19 }AUDIO_RANGE;
20
21 #define AUDIO_TEST_RANGE (5)
22
23 static AUDIO_RANGE TestRange[AUDIO_TEST_RANGE] =
24 {
25 {
26 11025,
27 WAVE_FORMAT_1M08,
28 WAVE_FORMAT_1S08,
29 WAVE_FORMAT_1M16,
30 WAVE_FORMAT_1S16
31 },
32 {
33 22050,
34 WAVE_FORMAT_2M08,
35 WAVE_FORMAT_2S08,
36 WAVE_FORMAT_2M16,
37 WAVE_FORMAT_2S16
38 },
39 {
40 44100,
41 WAVE_FORMAT_4M08,
42 WAVE_FORMAT_4S08,
43 WAVE_FORMAT_4M16,
44 WAVE_FORMAT_4S16
45 },
46 {
47 48000,
48 WAVE_FORMAT_48M08,
49 WAVE_FORMAT_48S08,
50 WAVE_FORMAT_48M16,
51 WAVE_FORMAT_48S16
52 },
53 {
54 96000,
55 WAVE_FORMAT_96M08,
56 WAVE_FORMAT_96S08,
57 WAVE_FORMAT_96M16,
58 WAVE_FORMAT_96S16
59 }
60 };
61
62 LPWAVE_INFO
63 AllocateWaveInfo()
64 {
65 /* allocate wav info */
66 LPWAVE_INFO WaveOutInfo = ExAllocatePool(NonPagedPool, sizeof(WAVE_INFO));
67 if (!WaveOutInfo)
68 return NULL;
69
70 /* zero wave info struct */
71 RtlZeroMemory(WaveOutInfo, sizeof(WAVE_INFO));
72
73 return WaveOutInfo;
74 }
75
76 PKSPIN_CONNECT
77 AllocatePinConnect(
78 ULONG DataFormatSize)
79 {
80 PKSPIN_CONNECT Connect = ExAllocatePool(NonPagedPool, sizeof(KSPIN_CONNECT) + DataFormatSize);
81 if (!Connect)
82 return NULL;
83
84 /* zero pin connect struct */
85 RtlZeroMemory(Connect, sizeof(KSPIN_CONNECT) + DataFormatSize);
86
87 return Connect;
88 }
89
90 NTSTATUS
91 GetWaveInfoByIndexAndType(
92 IN PDEVICE_OBJECT DeviceObject,
93 IN ULONG DeviceIndex,
94 IN SOUND_DEVICE_TYPE DeviceType,
95 OUT LPWAVE_INFO *OutWaveInfo)
96 {
97 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
98 ULONG Index = 0;
99 PLIST_ENTRY Entry, ListHead;
100 LPWAVE_INFO WaveInfo;
101
102 /* get device extension */
103 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
104
105 if (DeviceType == WAVE_IN_DEVICE_TYPE)
106 ListHead = &DeviceExtension->WaveInList;
107 else
108 ListHead = &DeviceExtension->WaveOutList;
109
110 /* get first entry */
111 Entry = ListHead->Flink;
112
113 while(Entry != ListHead)
114 {
115 WaveInfo = (LPWAVE_INFO)CONTAINING_RECORD(Entry, WAVE_INFO, Entry);
116
117 if (Index == DeviceIndex)
118 {
119 *OutWaveInfo = WaveInfo;
120 return STATUS_SUCCESS;
121 }
122 Index++;
123 Entry = Entry->Flink;
124 }
125
126 return STATUS_NOT_FOUND;
127 }
128
129
130 VOID
131 InitializePinConnect(
132 IN OUT PKSPIN_CONNECT PinConnect,
133 IN ULONG PinId)
134 {
135 PinConnect->Interface.Set = KSINTERFACESETID_Standard;
136 PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
137 PinConnect->Interface.Flags = 0;
138 PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
139 PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
140 PinConnect->Medium.Flags = 0;
141 PinConnect->PinToHandle = NULL;
142 PinConnect->PinId = PinId;
143 PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
144 PinConnect->Priority.PrioritySubClass = 1;
145 }
146
147 VOID
148 InitializeDataFormat(
149 IN PKSDATAFORMAT_WAVEFORMATEX DataFormat,
150 LPWAVEFORMATEX WaveFormatEx)
151 {
152
153 DataFormat->WaveFormatEx.wFormatTag = WaveFormatEx->wFormatTag;
154 DataFormat->WaveFormatEx.nChannels = WaveFormatEx->nChannels;
155 DataFormat->WaveFormatEx.nSamplesPerSec = WaveFormatEx->nSamplesPerSec;
156 DataFormat->WaveFormatEx.nBlockAlign = WaveFormatEx->nBlockAlign;
157 DataFormat->WaveFormatEx.nAvgBytesPerSec = WaveFormatEx->nAvgBytesPerSec;
158 DataFormat->WaveFormatEx.wBitsPerSample = WaveFormatEx->wBitsPerSample;
159 DataFormat->WaveFormatEx.cbSize = 0;
160 DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
161 DataFormat->DataFormat.Flags = 0;
162 DataFormat->DataFormat.Reserved = 0;
163 DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
164
165 DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
166 DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
167 DataFormat->DataFormat.SampleSize = 4;
168 }
169
170
171 NTSTATUS
172 AttachToVirtualAudioDevice(
173 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,
174 IN ULONG VirtualDeviceId)
175 {
176 ULONG BytesReturned;
177 SYSAUDIO_INSTANCE_INFO InstanceInfo;
178
179 /* setup property request */
180 InstanceInfo.Property.Set = KSPROPSETID_Sysaudio;
181 InstanceInfo.Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
182 InstanceInfo.Property.Flags = KSPROPERTY_TYPE_SET;
183 InstanceInfo.Flags = 0;
184 InstanceInfo.DeviceNumber = VirtualDeviceId;
185
186 /* attach to virtual device */
187 return KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
188
189 }
190
191 NTSTATUS
192 GetAudioPinDataRanges(
193 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,
194 IN ULONG FilterId,
195 IN ULONG PinId,
196 IN OUT PKSMULTIPLE_ITEM * OutMultipleItem)
197 {
198 KSP_PIN PinProperty;
199 ULONG BytesReturned = 0;
200 NTSTATUS Status;
201 PKSMULTIPLE_ITEM MultipleItem;
202
203 /* retrieve size of data ranges buffer */
204 PinProperty.Reserved = FilterId;
205 PinProperty.PinId = PinId;
206 PinProperty.Property.Set = KSPROPSETID_Pin;
207 PinProperty.Property.Id = KSPROPERTY_PIN_DATARANGES;
208 PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
209
210 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)NULL, 0, &BytesReturned);
211 if (Status != STATUS_MORE_ENTRIES)
212 {
213 return Status;
214 }
215
216 MultipleItem = ExAllocatePool(NonPagedPool, BytesReturned);
217 if (!MultipleItem)
218 {
219 /* not enough memory */
220 return STATUS_INSUFFICIENT_RESOURCES;
221 }
222
223 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
224 if (!NT_SUCCESS(Status))
225 {
226 /* failed */
227 ExFreePool(MultipleItem);
228 return Status;
229 }
230
231 /* save result */
232 *OutMultipleItem = MultipleItem;
233 return Status;
234 }
235
236 NTSTATUS
237 FindAudioDataRange(
238 PKSMULTIPLE_ITEM MultipleItem,
239 PKSDATARANGE_AUDIO * OutDataRangeAudio)
240 {
241 ULONG Index;
242 PKSDATARANGE_AUDIO DataRangeAudio;
243 PKSDATARANGE DataRange;
244
245 DataRange = (PKSDATARANGE) (MultipleItem + 1);
246 for(Index = 0; Index < MultipleItem->Count; Index++)
247 {
248 if (DataRange->FormatSize == sizeof(KSDATARANGE_AUDIO))
249 {
250 DataRangeAudio = (PKSDATARANGE_AUDIO)DataRange;
251 if (IsEqualGUIDAligned(&DataRangeAudio->DataRange.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
252 IsEqualGUIDAligned(&DataRangeAudio->DataRange.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
253 IsEqualGUIDAligned(&DataRangeAudio->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
254 {
255 DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio->MinimumSampleFrequency, DataRangeAudio->MaximumSampleFrequency,
256 DataRangeAudio->MinimumBitsPerSample, DataRangeAudio->MaximumBitsPerSample, DataRangeAudio->MaximumChannels);
257 *OutDataRangeAudio = DataRangeAudio;
258 return STATUS_SUCCESS;
259 }
260 }
261 }
262 return STATUS_UNSUCCESSFUL;
263 }
264
265 NTSTATUS
266 NTAPI
267 OpenWavePin(
268 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension,
269 IN ULONG FilterId,
270 IN ULONG PinId,
271 IN LPWAVEFORMATEX WaveFormatEx,
272 IN ACCESS_MASK DesiredAccess,
273 OUT PHANDLE PinHandle)
274 {
275 PKSPIN_CONNECT PinConnect;
276 PKSDATAFORMAT_WAVEFORMATEX DataFormat;
277 NTSTATUS Status;
278
279 /* allocate pin connect */
280 PinConnect = AllocatePinConnect(sizeof(KSDATAFORMAT_WAVEFORMATEX));
281 if (!PinConnect)
282 {
283 /* no memory */
284 return STATUS_INSUFFICIENT_RESOURCES;
285 }
286
287 /* initialize pin connect struct */
288 InitializePinConnect(PinConnect, PinId);
289
290 /* get offset to dataformat */
291 DataFormat = (PKSDATAFORMAT_WAVEFORMATEX) (PinConnect + 1);
292 /* initialize with requested wave format */
293 InitializeDataFormat(DataFormat, WaveFormatEx);
294
295 /* first attach to the virtual device */
296 Status = AttachToVirtualAudioDevice(DeviceExtension, FilterId);
297
298 if (!NT_SUCCESS(Status))
299 {
300 /* failed */
301 ExFreePool(PinConnect);
302 return Status;
303 }
304
305 /* now create the pin */
306 Status = KsCreatePin(DeviceExtension->hSysAudio, PinConnect, DesiredAccess, PinHandle);
307
308 /* free create info */
309 ExFreePool(PinConnect);
310
311 return Status;
312 }
313
314 ULONG
315 GetPinInstanceCount(
316 PWDMAUD_DEVICE_EXTENSION DeviceExtension,
317 ULONG FilterId,
318 ULONG PinId)
319 {
320 KSP_PIN PinRequest;
321 KSPIN_CINSTANCES PinInstances;
322 ULONG BytesReturned;
323 NTSTATUS Status;
324
325 /* query the instance count */
326 PinRequest.Reserved = FilterId;
327 PinRequest.PinId = PinId;
328 PinRequest.Property.Set = KSPROPSETID_Pin;
329 PinRequest.Property.Flags = KSPROPERTY_TYPE_GET;
330 PinRequest.Property.Id = KSPROPERTY_PIN_CINSTANCES;
331
332 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinRequest, sizeof(KSP_PIN), (PVOID)&PinInstances, sizeof(KSPIN_CINSTANCES), &BytesReturned);
333 ASSERT(Status == STATUS_SUCCESS);
334 return PinInstances.CurrentCount;
335 }
336
337
338 NTSTATUS
339 CheckSampleFormat(
340 PWDMAUD_DEVICE_EXTENSION DeviceExtension,
341 LPWAVE_INFO WaveInfo,
342 ULONG SampleRate,
343 ULONG NumChannels,
344 ULONG BitsPerSample)
345 {
346 NTSTATUS Status = STATUS_SUCCESS;
347 #if 0
348
349 WAVEFORMATEX WaveFormat;
350 HANDLE PinHandle;
351
352 /* clear wave format */
353 RtlZeroMemory(&WaveFormat, sizeof(WAVEFORMATEX));
354
355 WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
356 WaveFormat.nChannels = NumChannels;
357 WaveFormat.nSamplesPerSec = SampleRate;
358 WaveFormat.nAvgBytesPerSec = SampleRate * NumChannels * (BitsPerSample/8);
359 WaveFormat.nBlockAlign = (NumChannels * BitsPerSample) / 8;
360 WaveFormat.wBitsPerSample = BitsPerSample;
361 WaveFormat.cbSize = sizeof(WAVEFORMATEX);
362
363 Status = OpenWavePin(DeviceExtension, WaveInfo->FilterId, WaveInfo->PinId, &WaveFormat, GENERIC_READ | GENERIC_WRITE, &PinHandle);
364
365 if (NT_SUCCESS(Status))
366 {
367 /* success */
368 ZwClose(PinHandle);
369
370 while(GetPinInstanceCount(DeviceExtension, WaveInfo->FilterId, WaveInfo->PinId))
371 KeStallExecutionProcessor(5);
372 }
373
374 DPRINT("SampleRate %u BitsPerSample %u NumChannels %u Status %x bInput %u\n", SampleRate, BitsPerSample, NumChannels, Status, WaveInfo->bInput);
375 #endif
376
377
378 return Status;
379 }
380
381
382 NTSTATUS
383 CheckFormat(
384 PWDMAUD_DEVICE_EXTENSION DeviceExtension,
385 PKSDATARANGE_AUDIO DataRangeAudio,
386 LPWAVE_INFO WaveInfo)
387 {
388 ULONG Index, SampleFrequency;
389 ULONG Result = 0;
390 NTSTATUS Status;
391
392 for(Index = 0; Index < AUDIO_TEST_RANGE; Index++)
393 {
394 SampleFrequency = TestRange[Index].SampleRate;
395
396 if (DataRangeAudio->MinimumSampleFrequency <= SampleFrequency && DataRangeAudio->MaximumSampleFrequency >= SampleFrequency)
397 {
398 /* the audio adapter supports the sample frequency */
399 if (DataRangeAudio->MinimumBitsPerSample <= 8 && DataRangeAudio->MaximumBitsPerSample >= 8)
400 {
401 /* check if pin supports the sample rate in 8-Bit Mono */
402 Status = CheckSampleFormat(DeviceExtension, WaveInfo, SampleFrequency, 1, 8);
403 if (NT_SUCCESS(Status))
404 {
405 Result |= TestRange[Index].Bit8Mono;
406 }
407
408 if (DataRangeAudio->MaximumChannels > 1)
409 {
410 /* check if pin supports the sample rate in 8-Bit Stereo */
411 Status = CheckSampleFormat(DeviceExtension, WaveInfo, SampleFrequency, 2, 8);
412 if (NT_SUCCESS(Status))
413 {
414 Result |= TestRange[Index].Bit8Stereo;
415 }
416 }
417 }
418
419 if (DataRangeAudio->MinimumBitsPerSample <= 16 && DataRangeAudio->MaximumBitsPerSample >= 16)
420 {
421 /* check if pin supports the sample rate in 16-Bit Mono */
422 Status = CheckSampleFormat(DeviceExtension, WaveInfo, SampleFrequency, 1, 16);
423 if (NT_SUCCESS(Status))
424 {
425 Result |= TestRange[Index].Bit16Mono;
426 }
427
428 if (DataRangeAudio->MaximumChannels > 1)
429 {
430 /* check if pin supports the sample rate in 16-Bit Stereo */
431 Status = CheckSampleFormat(DeviceExtension, WaveInfo, SampleFrequency, 2, 16);
432 if (NT_SUCCESS(Status))
433 {
434 Result |= TestRange[Index].Bit16Stereo;
435 }
436 }
437 }
438 }
439 }
440
441
442 if (WaveInfo->bInput)
443 WaveInfo->u.InCaps.dwFormats = Result;
444 else
445 WaveInfo->u.OutCaps.dwFormats = Result;
446
447 DPRINT("Format %x bInput %u\n", Result, WaveInfo->bInput);
448
449
450 return STATUS_SUCCESS;
451 }
452
453 NTSTATUS
454 InitializeWaveInfo(
455 IN PDEVICE_OBJECT DeviceObject,
456 IN ULONG FilterId,
457 IN ULONG PinId,
458 IN ULONG bInput)
459 {
460 KSP_PIN PinProperty;
461 KSCOMPONENTID ComponentId;
462 NTSTATUS Status;
463 ULONG BytesReturned;
464 WCHAR DeviceName[MAX_PATH];
465 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
466 PKSMULTIPLE_ITEM MultipleItem;
467 PKSDATARANGE_AUDIO DataRangeAudio;
468 LPWAVE_INFO WaveInfo = AllocateWaveInfo();
469
470
471 if (!WaveInfo)
472 return STATUS_INSUFFICIENT_RESOURCES;
473
474 /* initialize wave info */
475 WaveInfo->bInput = bInput;
476 WaveInfo->FilterId = FilterId;
477 WaveInfo->PinId = PinId;
478
479 /* setup request to return component id */
480 PinProperty.PinId = FilterId;
481 PinProperty.Property.Set = KSPROPSETID_Sysaudio;
482 PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_COMPONENT_ID;
483 PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
484
485 /* get device extension */
486 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
487
488 /* query sysaudio for component id */
489 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)&ComponentId, sizeof(KSCOMPONENTID), &BytesReturned);
490 if (NT_SUCCESS(Status))
491 {
492 if (bInput)
493 {
494 WaveInfo->u.InCaps.wMid = ComponentId.Manufacturer.Data1 - 0xd5a47fa7;
495 WaveInfo->u.InCaps.vDriverVersion = MAKELONG(ComponentId.Version, ComponentId.Revision);
496 }
497 else
498 {
499 WaveInfo->u.OutCaps.wMid = ComponentId.Manufacturer.Data1 - 0xd5a47fa7;
500 WaveInfo->u.OutCaps.vDriverVersion = MAKELONG(ComponentId.Version, ComponentId.Revision);
501 }
502 }
503 else
504 {
505 /* set up something useful */
506 if (bInput)
507 {
508 WaveInfo->u.InCaps.wMid = MM_MICROSOFT;
509 WaveInfo->u.InCaps.wPid = MM_PID_UNMAPPED;
510 WaveInfo->u.InCaps.vDriverVersion = 1;
511 }
512 else
513 {
514 WaveInfo->u.OutCaps.wMid = MM_MICROSOFT;
515 WaveInfo->u.OutCaps.wPid = MM_PID_UNMAPPED;
516 WaveInfo->u.OutCaps.vDriverVersion = 1;
517 }
518 }
519
520 /* retrieve pnp base name */
521 PinProperty.PinId = FilterId;
522 PinProperty.Property.Set = KSPROPSETID_Sysaudio;
523 PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
524 PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
525
526 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)DeviceName, sizeof(DeviceName), &BytesReturned);
527 if (NT_SUCCESS(Status))
528 {
529 /* find product name */
530 if (bInput)
531 Status = FindProductName(DeviceName, MAXPNAMELEN, WaveInfo->u.OutCaps.szPname);
532 else
533 Status = FindProductName(DeviceName, MAXPNAMELEN, WaveInfo->u.InCaps.szPname);
534
535 /* check for success */
536 if (!NT_SUCCESS(Status))
537 {
538 if (bInput)
539 WaveInfo->u.OutCaps.szPname[0] = L'\0';
540 else
541 WaveInfo->u.InCaps.szPname[0] = L'\0';
542 }
543 }
544
545 Status = GetAudioPinDataRanges(DeviceExtension, FilterId, PinId, &MultipleItem);
546 if (NT_SUCCESS(Status))
547 {
548 /* find a audio data range */
549 Status = FindAudioDataRange(MultipleItem, &DataRangeAudio);
550
551 if (NT_SUCCESS(Status))
552 {
553 if (bInput)
554 {
555 WaveInfo->u.InCaps.wChannels = DataRangeAudio->MaximumChannels;
556 }
557 else
558 {
559 WaveInfo->u.OutCaps.wChannels = DataRangeAudio->MaximumChannels;
560 }
561 CheckFormat(DeviceExtension, DataRangeAudio, WaveInfo);
562 }
563 ExFreePool(MultipleItem);
564 }
565
566 if (bInput)
567 {
568 InsertTailList(&DeviceExtension->WaveInList, &WaveInfo->Entry);
569 DeviceExtension->WaveInDeviceCount++;
570 }
571 else
572 {
573 InsertTailList(&DeviceExtension->WaveOutList, &WaveInfo->Entry);
574 DeviceExtension->WaveOutDeviceCount++;
575 }
576
577
578 return STATUS_SUCCESS;
579 }
580
581
582 NTSTATUS
583 NTAPI
584 WdmAudWaveInitialize(
585 IN PDEVICE_OBJECT DeviceObject)
586 {
587 KSP_PIN Pin;
588 ULONG Count, BytesReturned, Index, SubIndex, Result, NumPins;
589 NTSTATUS Status;
590 KSPIN_COMMUNICATION Communication;
591 KSPIN_DATAFLOW DataFlow;
592 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
593
594 Pin.Property.Set = KSPROPSETID_Sysaudio;
595 Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
596 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
597
598 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
599
600 /* set wave count to zero */
601 DeviceExtension->WaveInDeviceCount = 0;
602 DeviceExtension->WaveOutDeviceCount = 0;
603
604 /* intialize list head */
605 InitializeListHead(&DeviceExtension->WaveInList);
606 InitializeListHead(&DeviceExtension->WaveOutList);
607
608 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
609 if (!NT_SUCCESS(Status))
610 return STATUS_UNSUCCESSFUL;
611
612 Result = 0;
613 for(Index = 0; Index < Count; Index++)
614 {
615 /* query number of pins */
616 Pin.Reserved = Index; // see sysaudio
617 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
618 Pin.Property.Set = KSPROPSETID_Pin;
619 Pin.Property.Id = KSPROPERTY_PIN_CTYPES;
620 Pin.PinId = 0;
621
622 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
623 if (NT_SUCCESS(Status))
624 {
625 /* enumerate now all pins */
626 for(SubIndex = 0; SubIndex < NumPins; SubIndex++)
627 {
628 Pin.PinId = SubIndex;
629 Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
630 Communication = KSPIN_COMMUNICATION_NONE;
631
632 /* get pin communication type */
633 KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
634
635 Pin.Property.Id = KSPROPERTY_PIN_DATAFLOW;
636 DataFlow = 0;
637
638 /* get pin dataflow type */
639 KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
640
641 if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
642 {
643 /* found a wave out device */
644 InitializeWaveInfo(DeviceObject, Index, SubIndex, FALSE);
645 }
646 else if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
647 {
648 /* found a wave in device */
649 InitializeWaveInfo(DeviceObject, Index, SubIndex, TRUE);
650 }
651 }
652 }
653 }
654
655 return STATUS_SUCCESS;
656 }
657
658 NTSTATUS
659 WdmAudControlOpenWave(
660 IN PDEVICE_OBJECT DeviceObject,
661 IN PIRP Irp,
662 IN PWDMAUD_DEVICE_INFO DeviceInfo,
663 IN PWDMAUD_CLIENT ClientInfo)
664 {
665 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
666 LPWAVE_INFO WaveInfo;
667 NTSTATUS Status;
668 ACCESS_MASK DesiredAccess = 0;
669 HANDLE PinHandle;
670 ULONG FreeIndex;
671
672 if (DeviceInfo->u.WaveFormatEx.wFormatTag != WAVE_FORMAT_PCM)
673 {
674 DPRINT("FIXME: Only WAVE_FORMAT_PCM is supported RequestFormat %x\n", DeviceInfo->u.WaveFormatEx.wFormatTag);
675 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
676 }
677
678 /* get device extension */
679 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
680
681 /* find destination wave */
682 Status = GetWaveInfoByIndexAndType(DeviceObject, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType, &WaveInfo);
683 if (!NT_SUCCESS(Status))
684 {
685 /* failed to find wave info */
686 DbgBreakPoint();
687 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
688 }
689
690 /* close pin handle which uses same virtual audio device id and pin id */
691 FreeIndex = ClosePin(ClientInfo, WaveInfo->FilterId, WaveInfo->PinId, DeviceInfo->DeviceType);
692
693 /* get desired access */
694 if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
695 {
696 DesiredAccess |= GENERIC_READ;
697 }
698 else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
699 {
700 DesiredAccess |= GENERIC_WRITE;
701 }
702
703 /* now try open the pin */
704 Status = OpenWavePin(DeviceExtension, WaveInfo->FilterId, WaveInfo->PinId, &DeviceInfo->u.WaveFormatEx, DesiredAccess, &PinHandle);
705
706 if (!NT_SUCCESS(Status))
707 {
708 /* failed to open the pin */
709 return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, 0);
710 }
711
712 /* store the handle */
713 Status = InsertPinHandle(ClientInfo, WaveInfo->FilterId, WaveInfo->PinId, DeviceInfo->DeviceType, PinHandle, FreeIndex);
714 if (!NT_SUCCESS(Status))
715 {
716 /* failed to insert handle */
717 ZwClose(PinHandle);
718 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
719 }
720
721 /* store pin handle */
722 DeviceInfo->hDevice = PinHandle;
723 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
724 }
725
726 NTSTATUS
727 WdmAudWaveCapabilities(
728 IN PDEVICE_OBJECT DeviceObject,
729 IN PWDMAUD_DEVICE_INFO DeviceInfo,
730 IN PWDMAUD_CLIENT ClientInfo,
731 IN PWDMAUD_DEVICE_EXTENSION DeviceExtension)
732 {
733 LPWAVE_INFO WaveInfo;
734 NTSTATUS Status;
735
736 /* find destination wave */
737 Status = GetWaveInfoByIndexAndType(DeviceObject, DeviceInfo->DeviceIndex, DeviceInfo->DeviceType, &WaveInfo);
738 if (!NT_SUCCESS(Status))
739 {
740 /* failed to find wave info */
741 DbgBreakPoint();
742 return STATUS_UNSUCCESSFUL;
743 }
744
745 if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
746 {
747 RtlMoveMemory(&DeviceInfo->u.WaveInCaps, &WaveInfo->u.InCaps, sizeof(WAVEINCAPSW));
748 }
749 else
750 {
751 RtlMoveMemory(&DeviceInfo->u.WaveOutCaps, &WaveInfo->u.OutCaps, sizeof(WAVEOUTCAPSW));
752 }
753
754 return STATUS_SUCCESS;
755 }
756