57057935ddb35b1bac7ceda4835d11eb41fa25a5
[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 SYSAUDIO_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 if (DeviceInfo->u.WaveFormatEx.wFormatTag != WAVE_FORMAT_PCM)
163 {
164 DPRINT("FIXME: Only WAVE_FORMAT_PCM is supported RequestFormat %x\n", DeviceInfo->u.WaveFormatEx.wFormatTag);
165 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
166 }
167
168 Status = GetFilterIdAndPinId(DeviceObject, DeviceInfo, ClientInfo, &FilterId, &PinId);
169 if (!NT_SUCCESS(Status))
170 {
171 DPRINT1("Invalid device index %u\n", DeviceInfo->DeviceIndex);
172 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
173 }
174
175 /* close pin handle which uses same virtual audio device id and pin id */
176 FreeIndex = (ULONG)-1;
177 for(Index = 0; Index < ClientInfo->NumPins; Index++)
178 {
179 if (ClientInfo->hPins[Index].FilterId == FilterId && ClientInfo->hPins[Index].PinId == PinId && ClientInfo->hPins[Index].Handle && ClientInfo->hPins[Index].Type == DeviceInfo->DeviceType)
180 {
181 ZwClose(ClientInfo->hPins[Index].Handle);
182 ClientInfo->hPins[Index].Handle = NULL;
183 FreeIndex = Index;
184 }
185 }
186
187
188 Length = sizeof(KSDATAFORMAT_WAVEFORMATEX) + sizeof(KSPIN_CONNECT);
189 PinConnect = ExAllocatePool(NonPagedPool, Length);
190 if (!PinConnect)
191 {
192 /* no memory */
193 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
194 }
195
196 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
197
198 if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE ||
199 DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE ||
200 DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
201 {
202 DesiredAccess |= GENERIC_READ;
203 }
204
205 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE ||
206 DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE ||
207 DeviceInfo->DeviceType == AUX_DEVICE_TYPE ||
208 DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
209 {
210 DesiredAccess |= GENERIC_WRITE;
211 }
212
213 PinConnect->Interface.Set = KSINTERFACESETID_Standard;
214 PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
215 PinConnect->Interface.Flags = 0;
216 PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
217 PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
218 PinConnect->Medium.Flags = 0;
219 PinConnect->PinToHandle = NULL;
220 PinConnect->PinId = PinId;
221 PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
222 PinConnect->Priority.PrioritySubClass = 1;
223
224
225 DataFormat = (KSDATAFORMAT_WAVEFORMATEX*) (PinConnect + 1);
226 DataFormat->WaveFormatEx.wFormatTag = DeviceInfo->u.WaveFormatEx.wFormatTag;
227 DataFormat->WaveFormatEx.nChannels = DeviceInfo->u.WaveFormatEx.nChannels;
228 DataFormat->WaveFormatEx.nSamplesPerSec = DeviceInfo->u.WaveFormatEx.nSamplesPerSec;
229 DataFormat->WaveFormatEx.nBlockAlign = DeviceInfo->u.WaveFormatEx.nBlockAlign;
230 DataFormat->WaveFormatEx.nAvgBytesPerSec = DeviceInfo->u.WaveFormatEx.nAvgBytesPerSec;
231 DataFormat->WaveFormatEx.wBitsPerSample = DeviceInfo->u.WaveFormatEx.wBitsPerSample;
232 DataFormat->WaveFormatEx.cbSize = 0;
233 DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
234 DataFormat->DataFormat.Flags = 0;
235 DataFormat->DataFormat.Reserved = 0;
236 DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
237
238 DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
239 DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
240 DataFormat->DataFormat.SampleSize = 4;
241
242 /* setup property request */
243 InstanceInfo.Property.Set = KSPROPSETID_Sysaudio;
244 InstanceInfo.Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
245 InstanceInfo.Property.Flags = KSPROPERTY_TYPE_SET;
246 InstanceInfo.Flags = 0;
247 InstanceInfo.DeviceNumber = FilterId;
248
249 /* first open the virtual device */
250 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
251
252 if (!NT_SUCCESS(Status))
253 {
254 /* failed */
255 ExFreePool(PinConnect);
256 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
257 }
258
259 /* now create the pin */
260 Status = KsCreatePin(DeviceExtension->hSysAudio, PinConnect, DesiredAccess, &PinHandle);
261
262 /* free create info */
263 ExFreePool(PinConnect);
264
265 if (NT_SUCCESS(Status))
266 {
267 PWDMAUD_HANDLE Handels;
268
269 if (FreeIndex != (ULONG)-1)
270 {
271 /* re-use a free index */
272 ClientInfo->hPins[Index].Handle = PinHandle;
273 ClientInfo->hPins[Index].FilterId = FilterId;
274 ClientInfo->hPins[Index].PinId = PinId;
275 ClientInfo->hPins[Index].Type = DeviceInfo->DeviceType;
276
277 DeviceInfo->hDevice = PinHandle;
278 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
279 }
280
281 Handels = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_HANDLE) * (ClientInfo->NumPins+1));
282
283 if (Handels)
284 {
285 if (ClientInfo->NumPins)
286 {
287 RtlMoveMemory(Handels, ClientInfo->hPins, sizeof(WDMAUD_HANDLE) * ClientInfo->NumPins);
288 ExFreePool(ClientInfo->hPins);
289 }
290
291 ClientInfo->hPins = Handels;
292 ClientInfo->hPins[ClientInfo->NumPins].Handle = PinHandle;
293 ClientInfo->hPins[ClientInfo->NumPins].Type = DeviceInfo->DeviceType;
294 ClientInfo->hPins[ClientInfo->NumPins].FilterId = FilterId;
295 ClientInfo->hPins[ClientInfo->NumPins].PinId = PinId;
296 ClientInfo->NumPins++;
297 }
298 DeviceInfo->hDevice = PinHandle;
299 }
300 else
301 {
302 DeviceInfo->hDevice = NULL;
303 }
304
305 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
306 }
307
308 NTSTATUS
309 WdmAudControlDeviceType(
310 IN PDEVICE_OBJECT DeviceObject,
311 IN PIRP Irp,
312 IN PWDMAUD_DEVICE_INFO DeviceInfo,
313 IN PWDMAUD_CLIENT ClientInfo)
314 {
315 KSP_PIN Pin;
316 ULONG Count, BytesReturned, Index, SubIndex, Result, NumPins;
317 NTSTATUS Status;
318 KSPIN_COMMUNICATION Communication;
319 KSPIN_DATAFLOW DataFlow;
320 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
321
322 if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
323 {
324 DeviceInfo->DeviceCount = GetNumOfMixerDevices(DeviceObject);
325 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
326 }
327
328 if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceInfo->DeviceType != WAVE_IN_DEVICE_TYPE)
329 {
330 DPRINT1("FIXME: Unsupported device type %x\n", DeviceInfo->DeviceType);
331 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
332 }
333
334 Pin.Property.Set = KSPROPSETID_Sysaudio;
335 Pin.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
336 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
337
338 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
339 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&Count, sizeof(ULONG), &BytesReturned);
340 if (!NT_SUCCESS(Status))
341 {
342 DPRINT1("KSPROPERTY_SYSAUDIO_DEVICE_COUNT failed with %x\n", Status);
343 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
344 }
345 Result = 0;
346 /* now enumerate all available filters */
347 for(Index = 0; Index < Count; Index++)
348 {
349 /* query number of pins */
350 Pin.Reserved = Index; // see sysaudio
351 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
352 Pin.Property.Set = KSPROPSETID_Pin;
353 Pin.Property.Id = KSPROPERTY_PIN_CTYPES;
354 Pin.PinId = 0;
355
356 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&NumPins, sizeof(ULONG), &BytesReturned);
357 if (NT_SUCCESS(Status))
358 {
359 /* enumerate now all pins */
360 for(SubIndex = 0; SubIndex < NumPins; SubIndex++)
361 {
362 Pin.PinId = SubIndex;
363 Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
364 Communication = KSPIN_COMMUNICATION_NONE;
365
366 /* get pin communication type */
367 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
368 if (!NT_SUCCESS(Status))
369 continue;
370
371 Pin.Property.Id = KSPROPERTY_PIN_DATAFLOW;
372 DataFlow = 0;
373
374 /* get pin dataflow type */
375 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)&DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
376 if (!NT_SUCCESS(Status))
377 continue;
378
379 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
380 {
381 if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
382 Result++;
383 }
384 else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
385 {
386 if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
387 Result++;
388 }
389 }
390 }
391 }
392
393 /* store result count */
394 DeviceInfo->DeviceCount = Result;
395
396 DPRINT1("WdmAudControlDeviceType Status %x Devices %u\n", Status, DeviceInfo->DeviceCount);
397 return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
398 }
399
400 NTSTATUS
401 WdmAudControlDeviceState(
402 IN PDEVICE_OBJECT DeviceObject,
403 IN PIRP Irp,
404 IN PWDMAUD_DEVICE_INFO DeviceInfo,
405 IN PWDMAUD_CLIENT ClientInfo)
406 {
407 KSPROPERTY Property;
408 KSSTATE State;
409 NTSTATUS Status;
410 ULONG BytesReturned;
411 PFILE_OBJECT FileObject;
412
413 //DPRINT1("WdmAudControlDeviceState\n");
414
415 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
416 if (!NT_SUCCESS(Status))
417 {
418 DPRINT1("Error: invalid device handle provided %p\n", DeviceInfo->hDevice);
419 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
420 }
421
422 Property.Set = KSPROPSETID_Connection;
423 Property.Id = KSPROPERTY_CONNECTION_STATE;
424 Property.Flags = KSPROPERTY_TYPE_SET;
425
426 State = DeviceInfo->u.State;
427
428 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned);
429
430 ObDereferenceObject(FileObject);
431
432 //DPRINT1("WdmAudControlDeviceState Status %x\n", Status);
433 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
434 }
435
436 ULONG
437 CheckFormatSupport(
438 IN PKSDATARANGE_AUDIO DataRangeAudio,
439 ULONG SampleFrequency,
440 ULONG Mono8Bit,
441 ULONG Stereo8Bit,
442 ULONG Mono16Bit,
443 ULONG Stereo16Bit)
444 {
445 ULONG Result = 0;
446
447 if (DataRangeAudio->MinimumSampleFrequency <= SampleFrequency && DataRangeAudio->MaximumSampleFrequency >= SampleFrequency)
448 {
449 if (DataRangeAudio->MinimumBitsPerSample <= 8 && DataRangeAudio->MaximumBitsPerSample >= 8)
450 {
451 Result |= Mono8Bit;
452 if (DataRangeAudio->MaximumChannels >= 2)
453 {
454 Result |= Stereo8Bit;
455 }
456 }
457
458 if (DataRangeAudio->MinimumBitsPerSample <= 16 && DataRangeAudio->MaximumBitsPerSample >= 16)
459 {
460 Result |= Mono16Bit;
461 if (DataRangeAudio->MaximumChannels >= 2)
462 {
463 Result |= Stereo8Bit;
464 }
465 }
466 }
467 return Result;
468
469 }
470
471 PKEY_VALUE_PARTIAL_INFORMATION
472 ReadKeyValue(
473 IN HANDLE hSubKey,
474 IN PUNICODE_STRING KeyName)
475 {
476 NTSTATUS Status;
477 ULONG Length;
478 PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
479
480 /* now query MatchingDeviceId key */
481 Status = ZwQueryValueKey(hSubKey, KeyName, KeyValuePartialInformation, NULL, 0, &Length);
482
483 /* check for success */
484 if (Status != STATUS_BUFFER_TOO_SMALL)
485 return NULL;
486
487 /* allocate a buffer for key data */
488 PartialInformation = ExAllocatePool(NonPagedPool, Length);
489
490 if (!PartialInformation)
491 return NULL;
492
493
494 /* now query MatchingDeviceId key */
495 Status = ZwQueryValueKey(hSubKey, KeyName, KeyValuePartialInformation, PartialInformation, Length, &Length);
496
497 /* check for success */
498 if (!NT_SUCCESS(Status))
499 {
500 ExFreePool(PartialInformation);
501 return NULL;
502 }
503
504 if (PartialInformation->Type != REG_SZ)
505 {
506 /* invalid key type */
507 ExFreePool(PartialInformation);
508 return NULL;
509 }
510
511 return PartialInformation;
512 }
513
514
515 NTSTATUS
516 CompareProductName(
517 IN HANDLE hSubKey,
518 IN LPWSTR PnpName,
519 IN ULONG ProductNameSize,
520 OUT LPWSTR ProductName)
521 {
522 PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
523 UNICODE_STRING DriverDescName = RTL_CONSTANT_STRING(L"DriverDesc");
524 UNICODE_STRING MatchingDeviceIdName = RTL_CONSTANT_STRING(L"MatchingDeviceId");
525 ULONG Length;
526 LPWSTR DeviceName;
527
528 /* read MatchingDeviceId value */
529 PartialInformation = ReadKeyValue(hSubKey, &MatchingDeviceIdName);
530
531 if (!PartialInformation)
532 return STATUS_UNSUCCESSFUL;
533
534
535 /* extract last '&' */
536 DeviceName = wcsrchr((LPWSTR)PartialInformation->Data, L'&');
537 ASSERT(DeviceName);
538 /* terminate it */
539 DeviceName[0] = L'\0';
540
541 Length = wcslen((LPWSTR)PartialInformation->Data);
542
543 DPRINT("DeviceName %S PnpName %S Length %u\n", (LPWSTR)PartialInformation->Data, PnpName, Length);
544
545 if (_wcsnicmp((LPWSTR)PartialInformation->Data, &PnpName[4], Length))
546 {
547 ExFreePool(PartialInformation);
548 return STATUS_NO_MATCH;
549 }
550
551 /* free buffer */
552 ExFreePool(PartialInformation);
553
554 /* read DriverDescName value */
555 PartialInformation = ReadKeyValue(hSubKey, &DriverDescName);
556
557 /* copy key name */
558 Length = min(ProductNameSize * sizeof(WCHAR), PartialInformation->DataLength);
559 RtlMoveMemory(ProductName, (PVOID)PartialInformation->Data, Length);
560
561 /* zero terminate it */
562 ProductName[ProductNameSize-1] = L'\0';
563
564 /* free buffer */
565 ExFreePool(PartialInformation);
566
567 return STATUS_SUCCESS;
568 }
569
570
571
572 NTSTATUS
573 FindProductName(
574 IN LPWSTR PnpName,
575 IN ULONG ProductNameSize,
576 OUT LPWSTR ProductName)
577 {
578 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E96C-E325-11CE-BFC1-08002BE10318}");
579
580 UNICODE_STRING SubKeyName;
581 WCHAR SubKey[20];
582 OBJECT_ATTRIBUTES ObjectAttributes;
583 HANDLE hKey, hSubKey;
584 NTSTATUS Status;
585 ULONG Length, Index;
586 PKEY_FULL_INFORMATION KeyInformation;
587
588 for(Index = 0; Index < wcslen(PnpName); Index++)
589 {
590 if (PnpName[Index] == '#')
591 PnpName[Index] = L'\\';
592 }
593
594
595 /* initialize key attributes */
596 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, NULL, NULL);
597
598 /* open the key */
599 Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjectAttributes);
600
601 /* check for success */
602 if (!NT_SUCCESS(Status))
603 return Status;
604
605 /* query num of subkeys */
606 Status = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &Length);
607
608 if (Status != STATUS_BUFFER_TOO_SMALL)
609 {
610 DPRINT1("ZwQueryKey failed with %x\n", Status);
611 /* failed */
612 ZwClose(hKey);
613 return Status;
614 }
615
616 /* allocate key information struct */
617 KeyInformation = ExAllocatePool(NonPagedPool, Length);
618 if (!KeyInformation)
619 {
620 /* no memory */
621 ZwClose(hKey);
622 return STATUS_INSUFFICIENT_RESOURCES;
623 }
624
625 /* query num of subkeys */
626 Status = ZwQueryKey(hKey, KeyFullInformation, (PVOID)KeyInformation, Length, &Length);
627
628 if (!NT_SUCCESS(Status))
629 {
630 DPRINT1("ZwQueryKey failed with %x\n", Status);
631 ExFreePool(KeyInformation);
632 ZwClose(hKey);
633 return Status;
634 }
635
636 /* now iterate through all subkeys */
637 for(Index = 0; Index < KeyInformation->SubKeys; Index++)
638 {
639 /* subkeys are always in the format 0000-XXXX */
640 swprintf(SubKey, L"%04u", Index);
641
642 /* initialize subkey name */
643 RtlInitUnicodeString(&SubKeyName, SubKey);
644
645 /* initialize key attributes */
646 InitializeObjectAttributes(&ObjectAttributes, &SubKeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, hKey, NULL);
647
648 /* open the sub key */
649 Status = ZwOpenKey(&hSubKey, GENERIC_READ, &ObjectAttributes);
650
651 /* check for success */
652 if (NT_SUCCESS(Status))
653 {
654 /* compare product name */
655 Status = CompareProductName(hSubKey, PnpName, ProductNameSize, ProductName);
656
657 /* close subkey */
658 ZwClose(hSubKey);
659
660 if (NT_SUCCESS(Status))
661 break;
662 }
663 }
664
665 /* free buffer */
666 ExFreePool(KeyInformation);
667
668 /* close key */
669 ZwClose(hKey);
670
671 /* no matching key found */
672 return Status;
673 }
674
675
676
677 NTSTATUS
678 WdmAudCapabilities(
679 IN PDEVICE_OBJECT DeviceObject,
680 IN PIRP Irp,
681 IN PWDMAUD_DEVICE_INFO DeviceInfo,
682 IN PWDMAUD_CLIENT ClientInfo)
683 {
684 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
685 NTSTATUS Status = STATUS_UNSUCCESSFUL;
686 KSP_PIN PinProperty;
687 KSCOMPONENTID ComponentId;
688 KSMULTIPLE_ITEM * MultipleItem;
689 ULONG BytesReturned;
690 PKSDATARANGE_AUDIO DataRangeAudio;
691 PKSDATARANGE DataRange;
692 ULONG Index;
693 ULONG wChannels = 0;
694 ULONG dwFormats = 0;
695 ULONG dwSupport = 0;
696 ULONG FilterId;
697 ULONG PinId;
698 WCHAR DeviceName[MAX_PATH];
699
700 DPRINT("WdmAudCapabilities entered\n");
701
702 Status = GetFilterIdAndPinId(DeviceObject, DeviceInfo, ClientInfo, &FilterId, &PinId);
703 if (!NT_SUCCESS(Status))
704 {
705 DPRINT1("Invalid device index provided %u\n", DeviceInfo->DeviceIndex);
706 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
707 }
708
709 PinProperty.PinId = FilterId;
710 PinProperty.Property.Set = KSPROPSETID_Sysaudio;
711 PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_COMPONENT_ID;
712 PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
713
714 RtlZeroMemory(&ComponentId, sizeof(KSCOMPONENTID));
715
716 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
717 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)&ComponentId, sizeof(KSCOMPONENTID), &BytesReturned);
718 if (NT_SUCCESS(Status))
719 {
720 DeviceInfo->u.WaveOutCaps.wMid = ComponentId.Manufacturer.Data1 - 0xd5a47fa7;
721 DeviceInfo->u.WaveOutCaps.vDriverVersion = MAKELONG(ComponentId.Version, ComponentId.Revision);
722 }
723
724 /* retrieve pnp base name */
725 PinProperty.PinId = FilterId;
726 PinProperty.Property.Set = KSPROPSETID_Sysaudio;
727 PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
728 PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
729
730 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)DeviceName, sizeof(DeviceName), &BytesReturned);
731 if (NT_SUCCESS(Status))
732 {
733 /* find product name */
734 Status = FindProductName(DeviceName, MAXPNAMELEN, DeviceInfo->u.WaveOutCaps.szPname);
735
736 /* check for success */
737 if (!NT_SUCCESS(Status))
738 {
739 DeviceInfo->u.WaveOutCaps.szPname[0] = L'\0';
740 }
741 }
742
743 PinProperty.Reserved = DeviceInfo->DeviceIndex;
744 PinProperty.PinId = PinId;
745 PinProperty.Property.Set = KSPROPSETID_Pin;
746 PinProperty.Property.Id = KSPROPERTY_PIN_DATARANGES;
747 PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
748
749 BytesReturned = 0;
750 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)NULL, 0, &BytesReturned);
751 if (Status != STATUS_BUFFER_TOO_SMALL)
752 {
753 return SetIrpIoStatus(Irp, Status, 0);
754 }
755
756 MultipleItem = ExAllocatePool(NonPagedPool, BytesReturned);
757 if (!MultipleItem)
758 {
759 /* no memory */
760 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
761 }
762
763 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
764 if (!NT_SUCCESS(Status))
765 {
766 ExFreePool(MultipleItem);
767 return SetIrpIoStatus(Irp, Status, 0);
768 }
769
770 DataRange = (PKSDATARANGE) (MultipleItem + 1);
771 for(Index = 0; Index < MultipleItem->Count; Index++)
772 {
773 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
774 {
775 if (DataRange->FormatSize == sizeof(KSDATARANGE_AUDIO))
776 {
777 DataRangeAudio = (PKSDATARANGE_AUDIO)DataRange;
778
779 if (IsEqualGUIDAligned(&DataRangeAudio->DataRange.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
780 IsEqualGUIDAligned(&DataRangeAudio->DataRange.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
781 IsEqualGUIDAligned(&DataRangeAudio->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
782 {
783 DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio->MinimumSampleFrequency, DataRangeAudio->MaximumSampleFrequency,
784 DataRangeAudio->MinimumBitsPerSample, DataRangeAudio->MaximumBitsPerSample, DataRangeAudio->MaximumChannels);
785
786 dwFormats |= CheckFormatSupport(DataRangeAudio, 11025, WAVE_FORMAT_1M08, WAVE_FORMAT_1S08, WAVE_FORMAT_1M16, WAVE_FORMAT_1S16);
787 dwFormats |= CheckFormatSupport(DataRangeAudio, 22050, WAVE_FORMAT_2M08, WAVE_FORMAT_2S08, WAVE_FORMAT_2M16, WAVE_FORMAT_2S16);
788 dwFormats |= CheckFormatSupport(DataRangeAudio, 44100, WAVE_FORMAT_4M08, WAVE_FORMAT_4S08, WAVE_FORMAT_4M16, WAVE_FORMAT_4S16);
789 dwFormats |= CheckFormatSupport(DataRangeAudio, 48000, WAVE_FORMAT_48M08, WAVE_FORMAT_48S08, WAVE_FORMAT_48M16, WAVE_FORMAT_48S16);
790 dwFormats |= CheckFormatSupport(DataRangeAudio, 96000, WAVE_FORMAT_96M08, WAVE_FORMAT_96S08, WAVE_FORMAT_96M16, WAVE_FORMAT_96S16);
791
792
793 wChannels = DataRangeAudio->MaximumChannels;
794 dwSupport = WAVECAPS_VOLUME; //FIXME get info from nodes
795 }
796 }
797 }
798 DataRange = (PKSDATARANGE)((PUCHAR)DataRange + DataRange->FormatSize);
799 }
800
801 DeviceInfo->u.WaveOutCaps.dwFormats = dwFormats;
802 DeviceInfo->u.WaveOutCaps.dwSupport = dwSupport;
803 DeviceInfo->u.WaveOutCaps.wChannels = wChannels;
804
805 ExFreePool(MultipleItem);
806
807 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
808 }
809
810 NTSTATUS
811 NTAPI
812 WdmAudIoctlClose(
813 IN PDEVICE_OBJECT DeviceObject,
814 IN PIRP Irp,
815 IN PWDMAUD_DEVICE_INFO DeviceInfo,
816 IN PWDMAUD_CLIENT ClientInfo)
817 {
818 ULONG Index;
819
820 for(Index = 0; Index < ClientInfo->NumPins; Index++)
821 {
822 if (ClientInfo->hPins[Index].Handle == DeviceInfo->hDevice && ClientInfo->hPins[Index].Type != MIXER_DEVICE_TYPE)
823 {
824 DPRINT1("Closing device %p\n", DeviceInfo->hDevice);
825 ZwClose(DeviceInfo->hDevice);
826 ClientInfo->hPins[Index].Handle = NULL;
827 SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
828 return STATUS_SUCCESS;
829 }
830 }
831 SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO));
832 return STATUS_INVALID_PARAMETER;
833 }
834
835 NTSTATUS
836 NTAPI
837 WdmAudFrameSize(
838 IN PDEVICE_OBJECT DeviceObject,
839 IN PIRP Irp,
840 IN PWDMAUD_DEVICE_INFO DeviceInfo,
841 IN PWDMAUD_CLIENT ClientInfo)
842 {
843 PFILE_OBJECT FileObject;
844 KSPROPERTY Property;
845 ULONG BytesReturned;
846 KSALLOCATOR_FRAMING Framing;
847 NTSTATUS Status;
848
849 /* Get sysaudio pin file object */
850 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
851 if (!NT_SUCCESS(Status))
852 {
853 DPRINT1("Invalid buffer handle %x\n", DeviceInfo->hDevice);
854 return SetIrpIoStatus(Irp, Status, 0);
855 }
856
857 /* Setup get framing request */
858 Property.Id = KSPROPERTY_CONNECTION_ALLOCATORFRAMING;
859 Property.Flags = KSPROPERTY_TYPE_GET;
860 Property.Set = KSPROPSETID_Connection;
861
862 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Framing, sizeof(KSALLOCATOR_FRAMING), &BytesReturned);
863 /* Did we succeed */
864 if (NT_SUCCESS(Status))
865 {
866 /* Store framesize */
867 DeviceInfo->u.FrameSize = Framing.FrameSize;
868 }
869
870 /* Release file object */
871 ObDereferenceObject(FileObject);
872
873 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
874
875 }
876
877
878 NTSTATUS
879 NTAPI
880 WdmAudDeviceControl(
881 IN PDEVICE_OBJECT DeviceObject,
882 IN PIRP Irp)
883 {
884 PIO_STACK_LOCATION IoStack;
885 PWDMAUD_DEVICE_INFO DeviceInfo;
886 PWDMAUD_CLIENT ClientInfo;
887
888 IoStack = IoGetCurrentIrpStackLocation(Irp);
889
890 DPRINT("WdmAudDeviceControl entered\n");
891
892 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(WDMAUD_DEVICE_INFO))
893 {
894 /* invalid parameter */
895 DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(WDMAUD_DEVICE_INFO));
896 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
897 }
898
899 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer;
900
901 if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE)
902 {
903 /* invalid parameter */
904 DPRINT1("Error: device type not set\n");
905 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
906 }
907
908 if (!IoStack->FileObject)
909 {
910 /* file object parameter */
911 DPRINT1("Error: file object is not attached\n");
912 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
913 }
914 ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
915
916 DPRINT("WdmAudDeviceControl entered\n");
917
918 switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
919 {
920 case IOCTL_OPEN_WDMAUD:
921 return WdmAudControlOpen(DeviceObject, Irp, DeviceInfo, ClientInfo);
922 case IOCTL_GETNUMDEVS_TYPE:
923 return WdmAudControlDeviceType(DeviceObject, Irp, DeviceInfo, ClientInfo);
924 case IOCTL_SETDEVICE_STATE:
925 return WdmAudControlDeviceState(DeviceObject, Irp, DeviceInfo, ClientInfo);
926 case IOCTL_GETCAPABILITIES:
927 return WdmAudCapabilities(DeviceObject, Irp, DeviceInfo, ClientInfo);
928 case IOCTL_CLOSE_WDMAUD:
929 return WdmAudIoctlClose(DeviceObject, Irp, DeviceInfo, ClientInfo);
930 case IOCTL_GETFRAMESIZE:
931 return WdmAudFrameSize(DeviceObject, Irp, DeviceInfo, ClientInfo);
932 case IOCTL_GETPOS:
933 case IOCTL_GETDEVID:
934 case IOCTL_GETVOLUME:
935 case IOCTL_SETVOLUME:
936
937 DPRINT1("Unhandeled %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
938 break;
939 }
940
941 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
942 }
943
944 NTSTATUS
945 NTAPI
946 WdmAudWriteCompletion(
947 IN PDEVICE_OBJECT DeviceObject,
948 IN PIRP LowerIrp,
949 IN PVOID Context)
950 {
951 PIRP Irp;
952 ASSERT(LowerIrp->PendingReturned == FALSE);
953 /* get original irp */
954 Irp = (PIRP)Context;
955
956 /* save status */
957 Irp->IoStatus.Status = LowerIrp->IoStatus.Status;
958 Irp->IoStatus.Information = LowerIrp->IoStatus.Information;
959 /* complete request */
960 IoCompleteRequest(Irp, IO_SOUND_INCREMENT);
961 /* return success to free irp */
962 return STATUS_SUCCESS;
963 }
964
965
966 NTSTATUS
967 NTAPI
968 WdmAudWrite(
969 IN PDEVICE_OBJECT DeviceObject,
970 IN PIRP Irp)
971 {
972 PIO_STACK_LOCATION IoStack;
973 PWDMAUD_DEVICE_INFO DeviceInfo;
974 PWDMAUD_CLIENT ClientInfo;
975 NTSTATUS Status = STATUS_SUCCESS;
976 PUCHAR Buffer;
977 PFILE_OBJECT FileObject;
978 PMDL Mdl;
979 //PIRP LowerIrp;
980 PCONTEXT_WRITE Packet;
981 PVOID SystemBuffer;
982 //LARGE_INTEGER Offset;
983 IO_STATUS_BLOCK IoStatusBlock;
984
985 IoStack = IoGetCurrentIrpStackLocation(Irp);
986
987 //DPRINT("WdmAudWrite entered\n");
988
989 if (IoStack->Parameters.Write.Length < sizeof(WDMAUD_DEVICE_INFO))
990 {
991 /* invalid parameter */
992 DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.Write.Length, sizeof(WDMAUD_DEVICE_INFO));
993 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
994 }
995
996 DeviceInfo = (PWDMAUD_DEVICE_INFO)MmGetMdlVirtualAddress(Irp->MdlAddress);
997
998
999 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
1000 if (!NT_SUCCESS(Status))
1001 {
1002 DPRINT1("Invalid buffer handle %x\n", DeviceInfo->hDevice);
1003 return SetIrpIoStatus(Irp, Status, 0);
1004 }
1005
1006
1007 //DPRINT("DeviceInfo %p %p %p\n", DeviceInfo, Irp->MdlAddress->StartVa, Irp->MdlAddress->MappedSystemVa);
1008 if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE)
1009 {
1010 /* invalid parameter */
1011 DPRINT1("Error: device type not set\n");
1012 ObDereferenceObject(FileObject);
1013 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1014 }
1015
1016 if (!IoStack->FileObject)
1017 {
1018 /* file object parameter */
1019 DPRINT1("Error: file object is not attached\n");
1020 ObDereferenceObject(FileObject);
1021 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
1022 }
1023 ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
1024
1025
1026 /* setup stream context */
1027 Packet = (PCONTEXT_WRITE)ExAllocatePool(NonPagedPool, sizeof(CONTEXT_WRITE));
1028 if (!Packet)
1029 {
1030 /* no memory */
1031 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
1032 }
1033
1034 Packet->Header.FrameExtent = DeviceInfo->BufferSize;
1035 Packet->Header.DataUsed = DeviceInfo->BufferSize;
1036 Packet->Header.Size = sizeof(KSSTREAM_HEADER);
1037 Packet->Header.PresentationTime.Numerator = 1;
1038 Packet->Header.PresentationTime.Denominator = 1;
1039 Packet->Irp = Irp;
1040
1041 Buffer = ExAllocatePool(NonPagedPool, DeviceInfo->BufferSize);
1042 if (!Buffer)
1043 {
1044 /* no memory */
1045 ExFreePool(Packet);
1046 ObDereferenceObject(FileObject);
1047 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
1048 }
1049 Packet->Header.Data = Buffer;
1050
1051 Mdl = IoAllocateMdl(DeviceInfo->Buffer, DeviceInfo->BufferSize, FALSE, FALSE, FALSE);
1052 if (!Mdl)
1053 {
1054 /* no memory */
1055 ExFreePool(Packet);
1056 ObDereferenceObject(FileObject);
1057 ExFreePool(Buffer);
1058 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
1059 }
1060
1061 _SEH2_TRY
1062 {
1063 MmProbeAndLockPages(Mdl, UserMode, IoReadAccess);
1064 }
1065 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1066 {
1067 /* Exception, get the error code */
1068 Status = _SEH2_GetExceptionCode();
1069 }
1070 _SEH2_END;
1071
1072 if (!NT_SUCCESS(Status))
1073 {
1074 DPRINT1("Invalid buffer supplied\n");
1075 ExFreePool(Buffer);
1076 ExFreePool(Packet);
1077 IoFreeMdl(Mdl);
1078 ObDereferenceObject(FileObject);
1079 return SetIrpIoStatus(Irp, Status, 0);
1080 }
1081
1082 SystemBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority );
1083 if (!SystemBuffer)
1084 {
1085 DPRINT1("Invalid buffer supplied\n");
1086 ExFreePool(Buffer);
1087 ExFreePool(Packet);
1088 IoFreeMdl(Mdl);
1089 ObDereferenceObject(FileObject);
1090 return SetIrpIoStatus(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
1091 }
1092
1093 RtlMoveMemory(Buffer, SystemBuffer, DeviceInfo->BufferSize);
1094 MmUnlockPages(Mdl);
1095 IoFreeMdl(Mdl);
1096
1097 #if 1
1098 KsStreamIo(FileObject, NULL, NULL, NULL, NULL, 0, &IoStatusBlock, Packet, sizeof(CONTEXT_WRITE), KSSTREAM_WRITE, UserMode);
1099 /* dereference file object */
1100 ObDereferenceObject(FileObject);
1101 return IoStatusBlock.Status;
1102 #else
1103 Offset.QuadPart = 0L;
1104
1105 /* now build the irp */
1106 LowerIrp = IoBuildAsynchronousFsdRequest (IRP_MJ_WRITE,
1107 IoGetRelatedDeviceObject(FileObject),
1108 Packet,
1109 sizeof(KSSTREAM_HEADER),
1110 &Offset,
1111 NULL);
1112
1113 if (!LowerIrp)
1114 {
1115 /* failed to create an associated irp */
1116 ExFreePool(Buffer);
1117 ExFreePool(Packet);
1118 ObDereferenceObject(FileObject);
1119
1120 return SetIrpIoStatus(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
1121 }
1122
1123 /* set a completion routine */
1124 IoSetCompletionRoutine(LowerIrp, WdmAudWriteCompletion, (PVOID)Irp, TRUE, TRUE, TRUE);
1125
1126 /* mark irp as pending */
1127 IoMarkIrpPending(Irp);
1128
1129 /* call the driver */
1130 Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), LowerIrp);
1131
1132 /* dereference file object */
1133 ObDereferenceObject(FileObject);
1134
1135 return STATUS_PENDING;
1136 #endif
1137 }