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