[KS]
[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 if (!PartialInformation)
558 {
559 /* failed to read driver desc key */
560 return STATUS_UNSUCCESSFUL;
561 }
562
563 /* copy key name */
564 Length = min(ProductNameSize * sizeof(WCHAR), PartialInformation->DataLength);
565 RtlMoveMemory(ProductName, (PVOID)PartialInformation->Data, Length);
566
567 /* zero terminate it */
568 ProductName[ProductNameSize-1] = L'\0';
569
570 /* free buffer */
571 ExFreePool(PartialInformation);
572
573 return STATUS_SUCCESS;
574 }
575
576
577
578 NTSTATUS
579 FindProductName(
580 IN LPWSTR PnpName,
581 IN ULONG ProductNameSize,
582 OUT LPWSTR ProductName)
583 {
584 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E96C-E325-11CE-BFC1-08002BE10318}");
585
586 UNICODE_STRING SubKeyName;
587 WCHAR SubKey[20];
588 OBJECT_ATTRIBUTES ObjectAttributes;
589 HANDLE hKey, hSubKey;
590 NTSTATUS Status;
591 ULONG Length, Index;
592 PKEY_FULL_INFORMATION KeyInformation;
593
594 for(Index = 0; Index < wcslen(PnpName); Index++)
595 {
596 if (PnpName[Index] == '#')
597 PnpName[Index] = L'\\';
598 }
599
600
601 /* initialize key attributes */
602 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, NULL, NULL);
603
604 /* open the key */
605 Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjectAttributes);
606
607 /* check for success */
608 if (!NT_SUCCESS(Status))
609 return Status;
610
611 /* query num of subkeys */
612 Status = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &Length);
613
614 if (Status != STATUS_BUFFER_TOO_SMALL)
615 {
616 DPRINT1("ZwQueryKey failed with %x\n", Status);
617 /* failed */
618 ZwClose(hKey);
619 return Status;
620 }
621
622 /* allocate key information struct */
623 KeyInformation = ExAllocatePool(NonPagedPool, Length);
624 if (!KeyInformation)
625 {
626 /* no memory */
627 ZwClose(hKey);
628 return STATUS_INSUFFICIENT_RESOURCES;
629 }
630
631 /* query num of subkeys */
632 Status = ZwQueryKey(hKey, KeyFullInformation, (PVOID)KeyInformation, Length, &Length);
633
634 if (!NT_SUCCESS(Status))
635 {
636 DPRINT1("ZwQueryKey failed with %x\n", Status);
637 ExFreePool(KeyInformation);
638 ZwClose(hKey);
639 return Status;
640 }
641
642 /* now iterate through all subkeys */
643 for(Index = 0; Index < KeyInformation->SubKeys; Index++)
644 {
645 /* subkeys are always in the format 0000-XXXX */
646 swprintf(SubKey, L"%04u", Index);
647
648 /* initialize subkey name */
649 RtlInitUnicodeString(&SubKeyName, SubKey);
650
651 /* initialize key attributes */
652 InitializeObjectAttributes(&ObjectAttributes, &SubKeyName, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, hKey, NULL);
653
654 /* open the sub key */
655 Status = ZwOpenKey(&hSubKey, GENERIC_READ, &ObjectAttributes);
656
657 /* check for success */
658 if (NT_SUCCESS(Status))
659 {
660 /* compare product name */
661 Status = CompareProductName(hSubKey, PnpName, ProductNameSize, ProductName);
662
663 /* close subkey */
664 ZwClose(hSubKey);
665
666 if (NT_SUCCESS(Status))
667 break;
668 }
669 }
670
671 /* free buffer */
672 ExFreePool(KeyInformation);
673
674 /* close key */
675 ZwClose(hKey);
676
677 /* no matching key found */
678 return Status;
679 }
680
681
682
683 NTSTATUS
684 WdmAudCapabilities(
685 IN PDEVICE_OBJECT DeviceObject,
686 IN PIRP Irp,
687 IN PWDMAUD_DEVICE_INFO DeviceInfo,
688 IN PWDMAUD_CLIENT ClientInfo)
689 {
690 PWDMAUD_DEVICE_EXTENSION DeviceExtension;
691 NTSTATUS Status = STATUS_UNSUCCESSFUL;
692 KSP_PIN PinProperty;
693 KSCOMPONENTID ComponentId;
694 KSMULTIPLE_ITEM * MultipleItem;
695 ULONG BytesReturned;
696 PKSDATARANGE_AUDIO DataRangeAudio;
697 PKSDATARANGE DataRange;
698 ULONG Index;
699 ULONG wChannels = 0;
700 ULONG dwFormats = 0;
701 ULONG dwSupport = 0;
702 ULONG FilterId;
703 ULONG PinId;
704 WCHAR DeviceName[MAX_PATH];
705
706 DPRINT("WdmAudCapabilities entered\n");
707
708 Status = GetFilterIdAndPinId(DeviceObject, DeviceInfo, ClientInfo, &FilterId, &PinId);
709 if (!NT_SUCCESS(Status))
710 {
711 DPRINT1("Invalid device index provided %u\n", DeviceInfo->DeviceIndex);
712 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
713 }
714
715 PinProperty.PinId = FilterId;
716 PinProperty.Property.Set = KSPROPSETID_Sysaudio;
717 PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_COMPONENT_ID;
718 PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
719
720 RtlZeroMemory(&ComponentId, sizeof(KSCOMPONENTID));
721
722 DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
723 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)&ComponentId, sizeof(KSCOMPONENTID), &BytesReturned);
724 if (NT_SUCCESS(Status))
725 {
726 DeviceInfo->u.WaveOutCaps.wMid = ComponentId.Manufacturer.Data1 - 0xd5a47fa7;
727 DeviceInfo->u.WaveOutCaps.vDriverVersion = MAKELONG(ComponentId.Version, ComponentId.Revision);
728 }
729
730 /* retrieve pnp base name */
731 PinProperty.PinId = FilterId;
732 PinProperty.Property.Set = KSPROPSETID_Sysaudio;
733 PinProperty.Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME;
734 PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
735
736 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)DeviceName, sizeof(DeviceName), &BytesReturned);
737 if (NT_SUCCESS(Status))
738 {
739 /* find product name */
740 Status = FindProductName(DeviceName, MAXPNAMELEN, DeviceInfo->u.WaveOutCaps.szPname);
741
742 /* check for success */
743 if (!NT_SUCCESS(Status))
744 {
745 DeviceInfo->u.WaveOutCaps.szPname[0] = L'\0';
746 }
747 }
748
749 PinProperty.Reserved = DeviceInfo->DeviceIndex;
750 PinProperty.PinId = PinId;
751 PinProperty.Property.Set = KSPROPSETID_Pin;
752 PinProperty.Property.Id = KSPROPERTY_PIN_DATARANGES;
753 PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
754
755 BytesReturned = 0;
756 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)NULL, 0, &BytesReturned);
757 if (Status != STATUS_BUFFER_TOO_SMALL)
758 {
759 return SetIrpIoStatus(Irp, Status, 0);
760 }
761
762 MultipleItem = ExAllocatePool(NonPagedPool, BytesReturned);
763 if (!MultipleItem)
764 {
765 /* no memory */
766 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
767 }
768
769 Status = KsSynchronousIoControlDevice(DeviceExtension->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
770 if (!NT_SUCCESS(Status))
771 {
772 ExFreePool(MultipleItem);
773 return SetIrpIoStatus(Irp, Status, 0);
774 }
775
776 DataRange = (PKSDATARANGE) (MultipleItem + 1);
777 for(Index = 0; Index < MultipleItem->Count; Index++)
778 {
779 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
780 {
781 if (DataRange->FormatSize == sizeof(KSDATARANGE_AUDIO))
782 {
783 DataRangeAudio = (PKSDATARANGE_AUDIO)DataRange;
784
785 if (IsEqualGUIDAligned(&DataRangeAudio->DataRange.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
786 IsEqualGUIDAligned(&DataRangeAudio->DataRange.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
787 IsEqualGUIDAligned(&DataRangeAudio->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
788 {
789 DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio->MinimumSampleFrequency, DataRangeAudio->MaximumSampleFrequency,
790 DataRangeAudio->MinimumBitsPerSample, DataRangeAudio->MaximumBitsPerSample, DataRangeAudio->MaximumChannels);
791
792 dwFormats |= CheckFormatSupport(DataRangeAudio, 11025, WAVE_FORMAT_1M08, WAVE_FORMAT_1S08, WAVE_FORMAT_1M16, WAVE_FORMAT_1S16);
793 dwFormats |= CheckFormatSupport(DataRangeAudio, 22050, WAVE_FORMAT_2M08, WAVE_FORMAT_2S08, WAVE_FORMAT_2M16, WAVE_FORMAT_2S16);
794 dwFormats |= CheckFormatSupport(DataRangeAudio, 44100, WAVE_FORMAT_4M08, WAVE_FORMAT_4S08, WAVE_FORMAT_4M16, WAVE_FORMAT_4S16);
795 dwFormats |= CheckFormatSupport(DataRangeAudio, 48000, WAVE_FORMAT_48M08, WAVE_FORMAT_48S08, WAVE_FORMAT_48M16, WAVE_FORMAT_48S16);
796 dwFormats |= CheckFormatSupport(DataRangeAudio, 96000, WAVE_FORMAT_96M08, WAVE_FORMAT_96S08, WAVE_FORMAT_96M16, WAVE_FORMAT_96S16);
797
798
799 wChannels = DataRangeAudio->MaximumChannels;
800 dwSupport = WAVECAPS_VOLUME; //FIXME get info from nodes
801 }
802 }
803 }
804 DataRange = (PKSDATARANGE)((PUCHAR)DataRange + DataRange->FormatSize);
805 }
806
807 DeviceInfo->u.WaveOutCaps.dwFormats = dwFormats;
808 DeviceInfo->u.WaveOutCaps.dwSupport = dwSupport;
809 DeviceInfo->u.WaveOutCaps.wChannels = wChannels;
810
811 ExFreePool(MultipleItem);
812
813 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
814 }
815
816 NTSTATUS
817 NTAPI
818 WdmAudIoctlClose(
819 IN PDEVICE_OBJECT DeviceObject,
820 IN PIRP Irp,
821 IN PWDMAUD_DEVICE_INFO DeviceInfo,
822 IN PWDMAUD_CLIENT ClientInfo)
823 {
824 ULONG Index;
825
826 for(Index = 0; Index < ClientInfo->NumPins; Index++)
827 {
828 if (ClientInfo->hPins[Index].Handle == DeviceInfo->hDevice && ClientInfo->hPins[Index].Type != MIXER_DEVICE_TYPE)
829 {
830 DPRINT1("Closing device %p\n", DeviceInfo->hDevice);
831 ZwClose(DeviceInfo->hDevice);
832 ClientInfo->hPins[Index].Handle = NULL;
833 SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
834 return STATUS_SUCCESS;
835 }
836 }
837 SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO));
838 return STATUS_INVALID_PARAMETER;
839 }
840
841 NTSTATUS
842 NTAPI
843 WdmAudFrameSize(
844 IN PDEVICE_OBJECT DeviceObject,
845 IN PIRP Irp,
846 IN PWDMAUD_DEVICE_INFO DeviceInfo,
847 IN PWDMAUD_CLIENT ClientInfo)
848 {
849 PFILE_OBJECT FileObject;
850 KSPROPERTY Property;
851 ULONG BytesReturned;
852 KSALLOCATOR_FRAMING Framing;
853 NTSTATUS Status;
854
855 /* Get sysaudio pin file object */
856 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
857 if (!NT_SUCCESS(Status))
858 {
859 DPRINT1("Invalid buffer handle %x\n", DeviceInfo->hDevice);
860 return SetIrpIoStatus(Irp, Status, 0);
861 }
862
863 /* Setup get framing request */
864 Property.Id = KSPROPERTY_CONNECTION_ALLOCATORFRAMING;
865 Property.Flags = KSPROPERTY_TYPE_GET;
866 Property.Set = KSPROPSETID_Connection;
867
868 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Framing, sizeof(KSALLOCATOR_FRAMING), &BytesReturned);
869 /* Did we succeed */
870 if (NT_SUCCESS(Status))
871 {
872 /* Store framesize */
873 DeviceInfo->u.FrameSize = Framing.FrameSize;
874 }
875
876 /* Release file object */
877 ObDereferenceObject(FileObject);
878
879 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
880
881 }
882
883
884 NTSTATUS
885 NTAPI
886 WdmAudDeviceControl(
887 IN PDEVICE_OBJECT DeviceObject,
888 IN PIRP Irp)
889 {
890 PIO_STACK_LOCATION IoStack;
891 PWDMAUD_DEVICE_INFO DeviceInfo;
892 PWDMAUD_CLIENT ClientInfo;
893
894 IoStack = IoGetCurrentIrpStackLocation(Irp);
895
896 DPRINT("WdmAudDeviceControl entered\n");
897
898 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(WDMAUD_DEVICE_INFO))
899 {
900 /* invalid parameter */
901 DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(WDMAUD_DEVICE_INFO));
902 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
903 }
904
905 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer;
906
907 if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE)
908 {
909 /* invalid parameter */
910 DPRINT1("Error: device type not set\n");
911 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
912 }
913
914 if (!IoStack->FileObject)
915 {
916 /* file object parameter */
917 DPRINT1("Error: file object is not attached\n");
918 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
919 }
920 ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
921
922 DPRINT("WdmAudDeviceControl entered\n");
923
924 switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
925 {
926 case IOCTL_OPEN_WDMAUD:
927 return WdmAudControlOpen(DeviceObject, Irp, DeviceInfo, ClientInfo);
928 case IOCTL_GETNUMDEVS_TYPE:
929 return WdmAudControlDeviceType(DeviceObject, Irp, DeviceInfo, ClientInfo);
930 case IOCTL_SETDEVICE_STATE:
931 return WdmAudControlDeviceState(DeviceObject, Irp, DeviceInfo, ClientInfo);
932 case IOCTL_GETCAPABILITIES:
933 return WdmAudCapabilities(DeviceObject, Irp, DeviceInfo, ClientInfo);
934 case IOCTL_CLOSE_WDMAUD:
935 return WdmAudIoctlClose(DeviceObject, Irp, DeviceInfo, ClientInfo);
936 case IOCTL_GETFRAMESIZE:
937 return WdmAudFrameSize(DeviceObject, Irp, DeviceInfo, ClientInfo);
938 case IOCTL_GETPOS:
939 case IOCTL_GETDEVID:
940 case IOCTL_GETVOLUME:
941 case IOCTL_SETVOLUME:
942
943 DPRINT1("Unhandeled %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
944 break;
945 }
946
947 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
948 }
949
950 NTSTATUS
951 NTAPI
952 WdmAudWriteCompletion(
953 IN PDEVICE_OBJECT DeviceObject,
954 IN PIRP LowerIrp,
955 IN PVOID Context)
956 {
957 //PIRP Irp;
958 ASSERT(LowerIrp->PendingReturned == FALSE);
959 /* get original irp */
960 //Irp = (PIRP)Context;
961
962 /* save status */
963 //Irp->IoStatus.Status = LowerIrp->IoStatus.Status;
964 //Irp->IoStatus.Information = LowerIrp->IoStatus.Information;
965 /* complete request */
966 //IoCompleteRequest(Irp, IO_SOUND_INCREMENT);
967 /* return success to free irp */
968 return STATUS_SUCCESS;
969 }
970
971
972 NTSTATUS
973 NTAPI
974 WdmAudWrite(
975 IN PDEVICE_OBJECT DeviceObject,
976 IN PIRP Irp)
977 {
978 PIO_STACK_LOCATION IoStack;
979 PWDMAUD_DEVICE_INFO DeviceInfo;
980 PWDMAUD_CLIENT ClientInfo;
981 NTSTATUS Status = STATUS_SUCCESS;
982 PUCHAR Buffer;
983 PFILE_OBJECT FileObject;
984 PMDL Mdl;
985 //PIRP LowerIrp;
986 PCONTEXT_WRITE Packet;
987 PVOID SystemBuffer;
988 //LARGE_INTEGER Offset;
989 IO_STATUS_BLOCK IoStatusBlock;
990
991 IoStack = IoGetCurrentIrpStackLocation(Irp);
992
993 //DPRINT("WdmAudWrite entered\n");
994
995 if (IoStack->Parameters.Write.Length < sizeof(WDMAUD_DEVICE_INFO))
996 {
997 /* invalid parameter */
998 DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.Write.Length, sizeof(WDMAUD_DEVICE_INFO));
999 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1000 }
1001
1002 DeviceInfo = (PWDMAUD_DEVICE_INFO)MmGetMdlVirtualAddress(Irp->MdlAddress);
1003
1004
1005 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
1006 if (!NT_SUCCESS(Status))
1007 {
1008 DPRINT1("Invalid buffer handle %x\n", DeviceInfo->hDevice);
1009 return SetIrpIoStatus(Irp, Status, 0);
1010 }
1011
1012
1013 //DPRINT("DeviceInfo %p %p %p\n", DeviceInfo, Irp->MdlAddress->StartVa, Irp->MdlAddress->MappedSystemVa);
1014 if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE)
1015 {
1016 /* invalid parameter */
1017 DPRINT1("Error: device type not set\n");
1018 ObDereferenceObject(FileObject);
1019 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
1020 }
1021
1022 if (!IoStack->FileObject)
1023 {
1024 /* file object parameter */
1025 DPRINT1("Error: file object is not attached\n");
1026 ObDereferenceObject(FileObject);
1027 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
1028 }
1029 ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
1030
1031
1032 /* setup stream context */
1033 Packet = (PCONTEXT_WRITE)ExAllocatePool(NonPagedPool, sizeof(CONTEXT_WRITE));
1034 if (!Packet)
1035 {
1036 /* no memory */
1037 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
1038 }
1039
1040 Packet->Header.FrameExtent = DeviceInfo->BufferSize;
1041 Packet->Header.DataUsed = DeviceInfo->BufferSize;
1042 Packet->Header.Size = sizeof(KSSTREAM_HEADER);
1043 Packet->Header.PresentationTime.Numerator = 1;
1044 Packet->Header.PresentationTime.Denominator = 1;
1045 Packet->Irp = Irp;
1046
1047 Buffer = ExAllocatePool(NonPagedPool, DeviceInfo->BufferSize);
1048 if (!Buffer)
1049 {
1050 /* no memory */
1051 ExFreePool(Packet);
1052 ObDereferenceObject(FileObject);
1053 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
1054 }
1055 Packet->Header.Data = Buffer;
1056
1057 Mdl = IoAllocateMdl(DeviceInfo->Buffer, DeviceInfo->BufferSize, FALSE, FALSE, FALSE);
1058 if (!Mdl)
1059 {
1060 /* no memory */
1061 ExFreePool(Packet);
1062 ObDereferenceObject(FileObject);
1063 ExFreePool(Buffer);
1064 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
1065 }
1066
1067 _SEH2_TRY
1068 {
1069 MmProbeAndLockPages(Mdl, UserMode, IoReadAccess);
1070 }
1071 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1072 {
1073 /* Exception, get the error code */
1074 Status = _SEH2_GetExceptionCode();
1075 }
1076 _SEH2_END;
1077
1078 if (!NT_SUCCESS(Status))
1079 {
1080 DPRINT1("Invalid buffer supplied\n");
1081 ExFreePool(Buffer);
1082 ExFreePool(Packet);
1083 IoFreeMdl(Mdl);
1084 ObDereferenceObject(FileObject);
1085 return SetIrpIoStatus(Irp, Status, 0);
1086 }
1087
1088 SystemBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority );
1089 if (!SystemBuffer)
1090 {
1091 DPRINT1("Invalid buffer supplied\n");
1092 ExFreePool(Buffer);
1093 ExFreePool(Packet);
1094 IoFreeMdl(Mdl);
1095 ObDereferenceObject(FileObject);
1096 return SetIrpIoStatus(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
1097 }
1098
1099 RtlMoveMemory(Buffer, SystemBuffer, DeviceInfo->BufferSize);
1100 MmUnlockPages(Mdl);
1101 IoFreeMdl(Mdl);
1102
1103 #if 1
1104 KsStreamIo(FileObject, NULL, NULL, NULL, NULL, 0, &IoStatusBlock, Packet, sizeof(CONTEXT_WRITE), KSSTREAM_WRITE, UserMode);
1105 /* dereference file object */
1106 ObDereferenceObject(FileObject);
1107 return IoStatusBlock.Status;
1108 #else
1109 Offset.QuadPart = 0L;
1110
1111 /* now build the irp */
1112 LowerIrp = IoBuildAsynchronousFsdRequest (IRP_MJ_WRITE,
1113 IoGetRelatedDeviceObject(FileObject),
1114 Packet,
1115 sizeof(KSSTREAM_HEADER),
1116 &Offset,
1117 NULL);
1118
1119 if (!LowerIrp)
1120 {
1121 /* failed to create an associated irp */
1122 ExFreePool(Buffer);
1123 ExFreePool(Packet);
1124 ObDereferenceObject(FileObject);
1125
1126 return SetIrpIoStatus(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
1127 }
1128
1129 /* get next stack location */
1130 IoStack = IoGetNextIrpStackLocation(LowerIrp);
1131
1132 /* attach file object */
1133 IoStack->FileObject = FileObject;
1134
1135 /* set a completion routine */
1136 IoSetCompletionRoutine(LowerIrp, WdmAudWriteCompletion, (PVOID)Irp, TRUE, TRUE, TRUE);
1137
1138 /* mark irp as pending */
1139 //IoMarkIrpPending(Irp);
1140 Irp->IoStatus.Information = DeviceInfo->BufferSize;
1141 Irp->IoStatus.Status = STATUS_SUCCESS;
1142 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1143 DPRINT1("Wrote %u\n", DeviceInfo->BufferSize);
1144 /* call the driver */
1145 Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), LowerIrp);
1146
1147 /* dereference file object */
1148 ObDereferenceObject(FileObject);
1149
1150 return STATUS_SUCCESS;
1151 #endif
1152 }