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