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