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