1c2c66affSColin Finck /*
2c2c66affSColin Finck  * COPYRIGHT:       See COPYING in the top level directory
3c2c66affSColin Finck  * PROJECT:         ReactOS Kernel Streaming
4c2c66affSColin Finck  * FILE:            drivers/wdm/audio/legacy/wdmaud/deviface.c
5c2c66affSColin Finck  * PURPOSE:         System Audio graph builder
6c2c66affSColin Finck  * PROGRAMMER:      Andrew Greenwood
7c2c66affSColin Finck  *                  Johannes Anderwald
8c2c66affSColin Finck  */
9c2c66affSColin Finck 
10c2c66affSColin Finck #include "wdmaud.h"
11c2c66affSColin Finck 
12c2c66affSColin Finck #define NDEBUG
13c2c66affSColin Finck #include <debug.h>
14c2c66affSColin Finck 
15c2c66affSColin Finck const GUID KSPROPSETID_Sysaudio                 = {0xCBE3FAA0L, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
16c2c66affSColin Finck 
17c2c66affSColin Finck NTSTATUS
WdmAudControlOpen(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)18c2c66affSColin Finck WdmAudControlOpen(
19c2c66affSColin Finck     IN  PDEVICE_OBJECT DeviceObject,
20c2c66affSColin Finck     IN  PIRP Irp,
21c2c66affSColin Finck     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
22c2c66affSColin Finck     IN  PWDMAUD_CLIENT ClientInfo)
23c2c66affSColin Finck {
24c2c66affSColin Finck     if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
25c2c66affSColin Finck     {
26c2c66affSColin Finck         return WdmAudControlOpenMixer(DeviceObject, Irp, DeviceInfo, ClientInfo);
27c2c66affSColin Finck     }
28c2c66affSColin Finck 
29c2c66affSColin Finck     if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
30c2c66affSColin Finck     {
31c2c66affSColin Finck         return WdmAudControlOpenWave(DeviceObject, Irp, DeviceInfo, ClientInfo);
32c2c66affSColin Finck     }
33c2c66affSColin Finck 
34c2c66affSColin Finck     if (DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE || DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE)
35c2c66affSColin Finck     {
36c2c66affSColin Finck         return WdmAudControlOpenMidi(DeviceObject, Irp, DeviceInfo, ClientInfo);
37c2c66affSColin Finck     }
38c2c66affSColin Finck 
39c2c66affSColin Finck 
40c2c66affSColin Finck     return SetIrpIoStatus(Irp, STATUS_NOT_SUPPORTED, sizeof(WDMAUD_DEVICE_INFO));
41c2c66affSColin Finck }
42c2c66affSColin Finck 
43c2c66affSColin Finck NTSTATUS
WdmAudControlDeviceType(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)44c2c66affSColin Finck WdmAudControlDeviceType(
45c2c66affSColin Finck     IN  PDEVICE_OBJECT DeviceObject,
46c2c66affSColin Finck     IN  PIRP Irp,
47c2c66affSColin Finck     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
48c2c66affSColin Finck     IN  PWDMAUD_CLIENT ClientInfo)
49c2c66affSColin Finck {
50c2c66affSColin Finck     ULONG Result = 0;
51c2c66affSColin Finck 
52c2c66affSColin Finck     if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
53c2c66affSColin Finck     {
54c2c66affSColin Finck         Result = WdmAudGetMixerDeviceCount();
55c2c66affSColin Finck     }
56c2c66affSColin Finck     else if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
57c2c66affSColin Finck     {
58c2c66affSColin Finck         Result = WdmAudGetWaveOutDeviceCount();
59c2c66affSColin Finck     }
60c2c66affSColin Finck     else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE)
61c2c66affSColin Finck     {
62c2c66affSColin Finck         Result = WdmAudGetWaveInDeviceCount();
63c2c66affSColin Finck     }
64c2c66affSColin Finck     else if (DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE)
65c2c66affSColin Finck     {
66c2c66affSColin Finck         Result = WdmAudGetMidiInDeviceCount();
67c2c66affSColin Finck     }
68c2c66affSColin Finck     else if (DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE)
69c2c66affSColin Finck     {
70c2c66affSColin Finck         Result = WdmAudGetMidiOutDeviceCount();
71c2c66affSColin Finck     }
72c2c66affSColin Finck 
73c2c66affSColin Finck 
74c2c66affSColin Finck     /* store result count */
75c2c66affSColin Finck     DeviceInfo->DeviceCount = Result;
76c2c66affSColin Finck 
77c2c66affSColin Finck     DPRINT("WdmAudControlDeviceType Devices %u\n", DeviceInfo->DeviceCount);
78c2c66affSColin Finck     return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
79c2c66affSColin Finck }
80c2c66affSColin Finck 
81c2c66affSColin Finck NTSTATUS
WdmAudControlDeviceState(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)82c2c66affSColin Finck WdmAudControlDeviceState(
83c2c66affSColin Finck     IN  PDEVICE_OBJECT DeviceObject,
84c2c66affSColin Finck     IN  PIRP Irp,
85c2c66affSColin Finck     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
86c2c66affSColin Finck     IN  PWDMAUD_CLIENT ClientInfo)
87c2c66affSColin Finck {
88c2c66affSColin Finck     KSPROPERTY Property;
89c2c66affSColin Finck     KSSTATE State;
90c2c66affSColin Finck     NTSTATUS Status;
91c2c66affSColin Finck     ULONG BytesReturned;
92c2c66affSColin Finck     PFILE_OBJECT FileObject;
93c2c66affSColin Finck 
94c2c66affSColin Finck     DPRINT("WdmAudControlDeviceState\n");
95c2c66affSColin Finck 
96c2c66affSColin Finck     Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
97c2c66affSColin Finck     if (!NT_SUCCESS(Status))
98c2c66affSColin Finck     {
99c2c66affSColin Finck         DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo->hDevice, DeviceInfo->DeviceType);
100c2c66affSColin Finck         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
101c2c66affSColin Finck     }
102c2c66affSColin Finck 
103c2c66affSColin Finck     Property.Set = KSPROPSETID_Connection;
104c2c66affSColin Finck     Property.Id = KSPROPERTY_CONNECTION_STATE;
105c2c66affSColin Finck     Property.Flags = KSPROPERTY_TYPE_SET;
106c2c66affSColin Finck 
107c2c66affSColin Finck     State = DeviceInfo->u.State;
108c2c66affSColin Finck 
109c2c66affSColin Finck     Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned);
110c2c66affSColin Finck 
111c2c66affSColin Finck     ObDereferenceObject(FileObject);
112c2c66affSColin Finck 
113c2c66affSColin Finck     DPRINT("WdmAudControlDeviceState Status %x\n", Status);
114c2c66affSColin Finck     return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
115c2c66affSColin Finck }
116c2c66affSColin Finck 
117c2c66affSColin Finck NTSTATUS
WdmAudCapabilities(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)118c2c66affSColin Finck WdmAudCapabilities(
119c2c66affSColin Finck     IN  PDEVICE_OBJECT DeviceObject,
120c2c66affSColin Finck     IN  PIRP Irp,
121c2c66affSColin Finck     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
122c2c66affSColin Finck     IN  PWDMAUD_CLIENT ClientInfo)
123c2c66affSColin Finck {
124c2c66affSColin Finck     PWDMAUD_DEVICE_EXTENSION DeviceExtension;
125c2c66affSColin Finck     NTSTATUS Status = STATUS_UNSUCCESSFUL;
126c2c66affSColin Finck 
127c2c66affSColin Finck     DPRINT("WdmAudCapabilities entered\n");
128c2c66affSColin Finck 
129c2c66affSColin Finck     DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
130c2c66affSColin Finck 
131c2c66affSColin Finck     if (DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
132c2c66affSColin Finck     {
133c2c66affSColin Finck         Status = WdmAudMixerCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
134c2c66affSColin Finck     }
135c2c66affSColin Finck     else if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE || DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE)
136c2c66affSColin Finck     {
137c2c66affSColin Finck         Status = WdmAudWaveCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
138c2c66affSColin Finck     }
139c2c66affSColin Finck     else if (DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE || DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE)
140c2c66affSColin Finck     {
141c2c66affSColin Finck         Status = WdmAudMidiCapabilities(DeviceObject, DeviceInfo, ClientInfo, DeviceExtension);
142c2c66affSColin Finck     }
143c2c66affSColin Finck 
144c2c66affSColin Finck     return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
145c2c66affSColin Finck }
146c2c66affSColin Finck 
147c2c66affSColin Finck NTSTATUS
148c2c66affSColin Finck NTAPI
WdmAudIoctlClose(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)149c2c66affSColin Finck WdmAudIoctlClose(
150c2c66affSColin Finck     IN  PDEVICE_OBJECT DeviceObject,
151c2c66affSColin Finck     IN  PIRP Irp,
152c2c66affSColin Finck     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
153c2c66affSColin Finck     IN  PWDMAUD_CLIENT ClientInfo)
154c2c66affSColin Finck {
155c2c66affSColin Finck     ULONG Index;
156c2c66affSColin Finck 
157c2c66affSColin Finck     for(Index = 0; Index < ClientInfo->NumPins; Index++)
158c2c66affSColin Finck     {
159c2c66affSColin Finck         if (ClientInfo->hPins[Index].Handle == DeviceInfo->hDevice && ClientInfo->hPins[Index].Type != MIXER_DEVICE_TYPE)
160c2c66affSColin Finck         {
161c2c66affSColin Finck             DPRINT1("Closing device %p\n", DeviceInfo->hDevice);
162c2c66affSColin Finck             ZwClose(DeviceInfo->hDevice);
163c2c66affSColin Finck             ClientInfo->hPins[Index].Handle = NULL;
164c2c66affSColin Finck             SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
165c2c66affSColin Finck             return STATUS_SUCCESS;
166c2c66affSColin Finck         }
167c2c66affSColin Finck         else if (ClientInfo->hPins[Index].Handle == DeviceInfo->hDevice && ClientInfo->hPins[Index].Type == MIXER_DEVICE_TYPE)
168c2c66affSColin Finck         {
169c2c66affSColin Finck             DPRINT1("Closing mixer %p\n", DeviceInfo->hDevice);
170c2c66affSColin Finck             return WdmAudControlCloseMixer(DeviceObject, Irp, DeviceInfo, ClientInfo, Index);
171c2c66affSColin Finck         }
172c2c66affSColin Finck     }
173c2c66affSColin Finck 
174c2c66affSColin Finck     SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, sizeof(WDMAUD_DEVICE_INFO));
175c2c66affSColin Finck     return STATUS_INVALID_PARAMETER;
176c2c66affSColin Finck }
177c2c66affSColin Finck 
178c2c66affSColin Finck NTSTATUS
179c2c66affSColin Finck NTAPI
WdmAudFrameSize(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo,IN PWDMAUD_CLIENT ClientInfo)180c2c66affSColin Finck WdmAudFrameSize(
181c2c66affSColin Finck     IN  PDEVICE_OBJECT DeviceObject,
182c2c66affSColin Finck     IN  PIRP Irp,
183c2c66affSColin Finck     IN  PWDMAUD_DEVICE_INFO DeviceInfo,
184c2c66affSColin Finck     IN  PWDMAUD_CLIENT ClientInfo)
185c2c66affSColin Finck {
186c2c66affSColin Finck     PFILE_OBJECT FileObject;
187c2c66affSColin Finck     KSPROPERTY Property;
188c2c66affSColin Finck     ULONG BytesReturned;
189c2c66affSColin Finck     KSALLOCATOR_FRAMING Framing;
190c2c66affSColin Finck     NTSTATUS Status;
191c2c66affSColin Finck 
192c2c66affSColin Finck     /* Get sysaudio pin file object */
193c2c66affSColin Finck     Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
194c2c66affSColin Finck     if (!NT_SUCCESS(Status))
195c2c66affSColin Finck     {
196c2c66affSColin Finck         DPRINT1("Invalid buffer handle %p\n", DeviceInfo->hDevice);
197c2c66affSColin Finck         return SetIrpIoStatus(Irp, Status, 0);
198c2c66affSColin Finck     }
199c2c66affSColin Finck 
200c2c66affSColin Finck     /* Setup get framing request */
201c2c66affSColin Finck     Property.Id = KSPROPERTY_CONNECTION_ALLOCATORFRAMING;
202c2c66affSColin Finck     Property.Flags = KSPROPERTY_TYPE_GET;
203c2c66affSColin Finck     Property.Set = KSPROPSETID_Connection;
204c2c66affSColin Finck 
205c2c66affSColin Finck     Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Framing, sizeof(KSALLOCATOR_FRAMING), &BytesReturned);
206c2c66affSColin Finck     /* Did we succeed */
207c2c66affSColin Finck     if (NT_SUCCESS(Status))
208c2c66affSColin Finck     {
209c2c66affSColin Finck         /* Store framesize */
210c2c66affSColin Finck         DeviceInfo->u.FrameSize = Framing.FrameSize;
211c2c66affSColin Finck     }
212c2c66affSColin Finck 
213c2c66affSColin Finck     /* Release file object */
214c2c66affSColin Finck     ObDereferenceObject(FileObject);
215c2c66affSColin Finck 
216c2c66affSColin Finck     return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
217c2c66affSColin Finck 
218c2c66affSColin Finck }
219c2c66affSColin Finck 
220c2c66affSColin Finck NTSTATUS
221c2c66affSColin Finck NTAPI
WdmAudGetDeviceInterface(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo)222c2c66affSColin Finck WdmAudGetDeviceInterface(
223c2c66affSColin Finck     IN  PDEVICE_OBJECT DeviceObject,
224c2c66affSColin Finck     IN  PIRP Irp,
225c2c66affSColin Finck     IN  PWDMAUD_DEVICE_INFO DeviceInfo)
226c2c66affSColin Finck {
227c2c66affSColin Finck     NTSTATUS Status;
228c2c66affSColin Finck     LPWSTR Device;
229c2c66affSColin Finck     ULONG Size, Length;
230c2c66affSColin Finck 
231c2c66affSColin Finck     /* get device interface string input length */
232c2c66affSColin Finck     Size = DeviceInfo->u.Interface.DeviceInterfaceStringSize;
233c2c66affSColin Finck 
234c2c66affSColin Finck    /* get mixer info */
235c2c66affSColin Finck    Status = WdmAudGetPnpNameByIndexAndType(DeviceInfo->DeviceIndex, DeviceInfo->DeviceType, &Device);
236c2c66affSColin Finck 
237c2c66affSColin Finck    /* check for success */
238c2c66affSColin Finck    if (!NT_SUCCESS(Status))
239c2c66affSColin Finck    {
240c2c66affSColin Finck         /* invalid device id */
241c2c66affSColin Finck         return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
242c2c66affSColin Finck    }
243c2c66affSColin Finck 
244c2c66affSColin Finck    /* calculate length */
245c2c66affSColin Finck    Length = (wcslen(Device)+1) * sizeof(WCHAR);
246c2c66affSColin Finck 
247c2c66affSColin Finck     if (!Size)
248c2c66affSColin Finck     {
249c2c66affSColin Finck         /* store device interface size */
250c2c66affSColin Finck         DeviceInfo->u.Interface.DeviceInterfaceStringSize = Length;
251c2c66affSColin Finck     }
252c2c66affSColin Finck     else if (Size < Length)
253c2c66affSColin Finck     {
254c2c66affSColin Finck         /* buffer too small */
255c2c66affSColin Finck         DeviceInfo->u.Interface.DeviceInterfaceStringSize = Length;
256c2c66affSColin Finck         return SetIrpIoStatus(Irp, STATUS_BUFFER_OVERFLOW, sizeof(WDMAUD_DEVICE_INFO));
257c2c66affSColin Finck     }
258c2c66affSColin Finck     else
259c2c66affSColin Finck     {
260c2c66affSColin Finck         //FIXME SEH
261c2c66affSColin Finck         RtlMoveMemory(DeviceInfo->u.Interface.DeviceInterfaceString, Device, Length);
262c2c66affSColin Finck     }
263c2c66affSColin Finck 
264c2c66affSColin Finck     FreeItem(Device);
265c2c66affSColin Finck     return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
266c2c66affSColin Finck }
267c2c66affSColin Finck 
268c2c66affSColin Finck NTSTATUS
269c2c66affSColin Finck NTAPI
WdmAudResetStream(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PWDMAUD_DEVICE_INFO DeviceInfo)270c2c66affSColin Finck WdmAudResetStream(
271c2c66affSColin Finck     IN  PDEVICE_OBJECT DeviceObject,
272c2c66affSColin Finck     IN  PIRP Irp,
273c2c66affSColin Finck     IN  PWDMAUD_DEVICE_INFO DeviceInfo)
274c2c66affSColin Finck {
275c2c66affSColin Finck     KSRESET ResetStream;
276c2c66affSColin Finck     NTSTATUS Status;
277c2c66affSColin Finck     ULONG BytesReturned;
278c2c66affSColin Finck     PFILE_OBJECT FileObject;
279c2c66affSColin Finck 
280c2c66affSColin Finck     DPRINT("WdmAudResetStream\n");
281c2c66affSColin Finck 
282c2c66affSColin Finck     Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
283c2c66affSColin Finck     if (!NT_SUCCESS(Status))
284c2c66affSColin Finck     {
285c2c66affSColin Finck         DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo->hDevice, DeviceInfo->DeviceType);
286c2c66affSColin Finck         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
287c2c66affSColin Finck     }
288c2c66affSColin Finck 
289c2c66affSColin Finck     ResetStream = DeviceInfo->u.ResetStream;
290c2c66affSColin Finck     ASSERT(ResetStream == KSRESET_BEGIN || ResetStream == KSRESET_END);
291c2c66affSColin Finck 
292c2c66affSColin Finck     Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_RESET_STATE, (PVOID)&ResetStream, sizeof(KSRESET), NULL, 0, &BytesReturned);
293c2c66affSColin Finck 
294c2c66affSColin Finck     ObDereferenceObject(FileObject);
295c2c66affSColin Finck 
296c2c66affSColin Finck     DPRINT("WdmAudResetStream Status %x\n", Status);
297c2c66affSColin Finck     return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
298c2c66affSColin Finck }
299c2c66affSColin Finck 
300c2c66affSColin Finck NTSTATUS
301c2c66affSColin Finck NTAPI
WdmAudDeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)302c2c66affSColin Finck WdmAudDeviceControl(
303c2c66affSColin Finck     IN  PDEVICE_OBJECT DeviceObject,
304c2c66affSColin Finck     IN  PIRP Irp)
305c2c66affSColin Finck {
306c2c66affSColin Finck     PIO_STACK_LOCATION IoStack;
307c2c66affSColin Finck     PWDMAUD_DEVICE_INFO DeviceInfo;
308c2c66affSColin Finck     PWDMAUD_CLIENT ClientInfo;
309c2c66affSColin Finck 
310c2c66affSColin Finck     IoStack = IoGetCurrentIrpStackLocation(Irp);
311c2c66affSColin Finck 
312c2c66affSColin Finck     DPRINT("WdmAudDeviceControl entered\n");
313c2c66affSColin Finck 
314c2c66affSColin Finck     if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(WDMAUD_DEVICE_INFO))
315c2c66affSColin Finck     {
316c2c66affSColin Finck         /* invalid parameter */
317c2c66affSColin Finck         DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(WDMAUD_DEVICE_INFO));
318c2c66affSColin Finck         return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
319c2c66affSColin Finck     }
320c2c66affSColin Finck 
321c2c66affSColin Finck     DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer;
322c2c66affSColin Finck 
323c2c66affSColin Finck     if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE)
324c2c66affSColin Finck     {
325c2c66affSColin Finck         /* invalid parameter */
326c2c66affSColin Finck         DPRINT1("Error: device type not set\n");
327c2c66affSColin Finck         return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
328c2c66affSColin Finck     }
329c2c66affSColin Finck 
330c2c66affSColin Finck     if (!IoStack->FileObject || !IoStack->FileObject->FsContext)
331c2c66affSColin Finck     {
332c2c66affSColin Finck         /* file object parameter */
333c2c66affSColin Finck         DPRINT1("Error: file object is not attached\n");
334c2c66affSColin Finck         return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
335c2c66affSColin Finck     }
336c2c66affSColin Finck     ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
337c2c66affSColin Finck 
338c2c66affSColin Finck     DPRINT("WdmAudDeviceControl entered\n");
339c2c66affSColin Finck 
340c2c66affSColin Finck     switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
341c2c66affSColin Finck     {
342c2c66affSColin Finck         case IOCTL_OPEN_WDMAUD:
343c2c66affSColin Finck             return WdmAudControlOpen(DeviceObject, Irp, DeviceInfo, ClientInfo);
344c2c66affSColin Finck         case IOCTL_GETNUMDEVS_TYPE:
345c2c66affSColin Finck             return WdmAudControlDeviceType(DeviceObject, Irp, DeviceInfo, ClientInfo);
346c2c66affSColin Finck         case IOCTL_SETDEVICE_STATE:
347c2c66affSColin Finck             return WdmAudControlDeviceState(DeviceObject, Irp, DeviceInfo, ClientInfo);
348c2c66affSColin Finck         case IOCTL_GETCAPABILITIES:
349c2c66affSColin Finck             return WdmAudCapabilities(DeviceObject, Irp, DeviceInfo, ClientInfo);
350c2c66affSColin Finck         case IOCTL_CLOSE_WDMAUD:
351c2c66affSColin Finck             return WdmAudIoctlClose(DeviceObject, Irp, DeviceInfo, ClientInfo);
352c2c66affSColin Finck         case IOCTL_GETFRAMESIZE:
353c2c66affSColin Finck             return WdmAudFrameSize(DeviceObject, Irp, DeviceInfo, ClientInfo);
354c2c66affSColin Finck         case IOCTL_GETLINEINFO:
355c2c66affSColin Finck             return WdmAudGetLineInfo(DeviceObject, Irp, DeviceInfo, ClientInfo);
356c2c66affSColin Finck         case IOCTL_GETLINECONTROLS:
357c2c66affSColin Finck             return WdmAudGetLineControls(DeviceObject, Irp, DeviceInfo, ClientInfo);
358c2c66affSColin Finck         case IOCTL_SETCONTROLDETAILS:
359c2c66affSColin Finck             return WdmAudSetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo);
360c2c66affSColin Finck         case IOCTL_GETCONTROLDETAILS:
361c2c66affSColin Finck             return WdmAudGetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo);
362c2c66affSColin Finck         case IOCTL_QUERYDEVICEINTERFACESTRING:
363c2c66affSColin Finck             return WdmAudGetDeviceInterface(DeviceObject, Irp, DeviceInfo);
364c2c66affSColin Finck         case IOCTL_GET_MIXER_EVENT:
365c2c66affSColin Finck             return WdmAudGetMixerEvent(DeviceObject, Irp, DeviceInfo, ClientInfo);
366c2c66affSColin Finck         case IOCTL_RESET_STREAM:
367c2c66affSColin Finck             return WdmAudResetStream(DeviceObject, Irp, DeviceInfo);
368c2c66affSColin Finck         case IOCTL_GETPOS:
369*d1b8feb6SOleg Dubinskiy             return WdmAudGetPosition(DeviceObject, Irp, DeviceInfo);
370c2c66affSColin Finck         case IOCTL_GETDEVID:
371c2c66affSColin Finck         case IOCTL_GETVOLUME:
372c2c66affSColin Finck         case IOCTL_SETVOLUME:
373c2c66affSColin Finck 
374c2c66affSColin Finck            DPRINT1("Unhandled %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
375c2c66affSColin Finck            break;
376c2c66affSColin Finck     }
377c2c66affSColin Finck 
378c2c66affSColin Finck     return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
379c2c66affSColin Finck }
380c2c66affSColin Finck 
381c2c66affSColin Finck NTSTATUS
382c2c66affSColin Finck NTAPI
IoCompletion(PDEVICE_OBJECT DeviceObject,PIRP Irp,PVOID Ctx)383c2c66affSColin Finck IoCompletion (
384c2c66affSColin Finck     PDEVICE_OBJECT DeviceObject,
385c2c66affSColin Finck     PIRP Irp,
386c2c66affSColin Finck     PVOID Ctx)
387c2c66affSColin Finck {
388c2c66affSColin Finck     PKSSTREAM_HEADER Header;
389c2c66affSColin Finck     PMDL Mdl, NextMdl;
390c2c66affSColin Finck     PWDMAUD_COMPLETION_CONTEXT Context = (PWDMAUD_COMPLETION_CONTEXT)Ctx;
391c2c66affSColin Finck 
392c2c66affSColin Finck     /* get stream header */
393c2c66affSColin Finck     Header = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
394c2c66affSColin Finck 
395c2c66affSColin Finck     /* sanity check */
396c2c66affSColin Finck     ASSERT(Header);
397c2c66affSColin Finck 
398c2c66affSColin Finck     /* time to free all allocated mdls */
399c2c66affSColin Finck     Mdl = Irp->MdlAddress;
400c2c66affSColin Finck 
401c2c66affSColin Finck     while(Mdl)
402c2c66affSColin Finck     {
403c2c66affSColin Finck         /* get next mdl */
404c2c66affSColin Finck         NextMdl = Mdl->Next;
405c2c66affSColin Finck 
406c2c66affSColin Finck         /* unlock pages */
407c2c66affSColin Finck         MmUnlockPages(Mdl);
408c2c66affSColin Finck 
409c2c66affSColin Finck         /* grab next mdl */
410c2c66affSColin Finck         Mdl = NextMdl;
411c2c66affSColin Finck     }
412c2c66affSColin Finck     //IoFreeMdl(Mdl);
413c2c66affSColin Finck     /* clear mdl list */
414c2c66affSColin Finck     Irp->MdlAddress = Context->Mdl;
415c2c66affSColin Finck 
416c2c66affSColin Finck 
417c2c66affSColin Finck 
418c2c66affSColin Finck     DPRINT("IoCompletion Irp %p IoStatus %lx Information %lx\n", Irp, Irp->IoStatus.Status, Irp->IoStatus.Information);
419c2c66affSColin Finck 
420c2c66affSColin Finck     if (!NT_SUCCESS(Irp->IoStatus.Status))
421c2c66affSColin Finck     {
422c2c66affSColin Finck         /* failed */
423c2c66affSColin Finck         Irp->IoStatus.Information = 0;
424c2c66affSColin Finck     }
425c2c66affSColin Finck 
426c2c66affSColin Finck     /* dereference file object */
427c2c66affSColin Finck     ObDereferenceObject(Context->FileObject);
428c2c66affSColin Finck 
429c2c66affSColin Finck     /* free context */
430c2c66affSColin Finck     FreeItem(Context);
431c2c66affSColin Finck 
432c2c66affSColin Finck     return STATUS_SUCCESS;
433c2c66affSColin Finck }
434c2c66affSColin Finck 
435c2c66affSColin Finck NTSTATUS
436c2c66affSColin Finck NTAPI
WdmAudReadWrite(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)437c2c66affSColin Finck WdmAudReadWrite(
438c2c66affSColin Finck     IN  PDEVICE_OBJECT DeviceObject,
439c2c66affSColin Finck     IN  PIRP Irp)
440c2c66affSColin Finck {
441c2c66affSColin Finck     NTSTATUS Status;
442c2c66affSColin Finck     PWDMAUD_DEVICE_INFO DeviceInfo;
443c2c66affSColin Finck     PFILE_OBJECT FileObject;
444c2c66affSColin Finck     PIO_STACK_LOCATION IoStack;
445c2c66affSColin Finck     ULONG Length;
446c2c66affSColin Finck     PMDL Mdl;
447c2c66affSColin Finck     BOOLEAN Read = TRUE;
448c2c66affSColin Finck     PWDMAUD_COMPLETION_CONTEXT Context;
449c2c66affSColin Finck 
450c2c66affSColin Finck     /* allocate completion context */
451c2c66affSColin Finck     Context = AllocateItem(NonPagedPool, sizeof(WDMAUD_COMPLETION_CONTEXT));
452c2c66affSColin Finck 
453c2c66affSColin Finck     if (!Context)
454c2c66affSColin Finck     {
455c2c66affSColin Finck         /* not enough memory */
456c2c66affSColin Finck         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
457c2c66affSColin Finck         IoCompleteRequest(Irp, IO_NO_INCREMENT);
458c2c66affSColin Finck 
459c2c66affSColin Finck         /* done */
460c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
461c2c66affSColin Finck     }
462c2c66affSColin Finck 
463c2c66affSColin Finck     /* get current irp stack location */
464c2c66affSColin Finck     IoStack = IoGetCurrentIrpStackLocation(Irp);
465c2c66affSColin Finck 
466c2c66affSColin Finck     /* store the input buffer in UserBuffer - as KsProbeStreamIrp operates on IRP_MJ_DEVICE_CONTROL */
467c2c66affSColin Finck     Irp->UserBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
468c2c66affSColin Finck 
469c2c66affSColin Finck     /* sanity check */
470c2c66affSColin Finck     ASSERT(Irp->UserBuffer);
471c2c66affSColin Finck 
472c2c66affSColin Finck     /* get the length of the request length */
473c2c66affSColin Finck     Length = IoStack->Parameters.Write.Length;
474c2c66affSColin Finck 
475c2c66affSColin Finck     /* store outputbuffer length */
476c2c66affSColin Finck     IoStack->Parameters.DeviceIoControl.OutputBufferLength = Length;
477c2c66affSColin Finck 
478c2c66affSColin Finck     /* setup context */
479c2c66affSColin Finck     Context->Length = Length;
480c2c66affSColin Finck     Context->Function = (IoStack->MajorFunction == IRP_MJ_WRITE ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM);
481c2c66affSColin Finck     Context->Mdl = Irp->MdlAddress;
482c2c66affSColin Finck 
483c2c66affSColin Finck     /* store mdl address */
484c2c66affSColin Finck     Mdl = Irp->MdlAddress;
485c2c66affSColin Finck 
486c2c66affSColin Finck     /* remove mdladdress as KsProbeStreamIrp will interpret it as an already probed audio buffer */
487c2c66affSColin Finck     Irp->MdlAddress = NULL;
488c2c66affSColin Finck 
489c2c66affSColin Finck     if (IoStack->MajorFunction == IRP_MJ_WRITE)
490c2c66affSColin Finck     {
491c2c66affSColin Finck         /* probe the write stream irp */
492c2c66affSColin Finck         Read = FALSE;
493c2c66affSColin Finck         Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMWRITE | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length);
494c2c66affSColin Finck     }
495c2c66affSColin Finck     else
496c2c66affSColin Finck     {
497c2c66affSColin Finck         /* probe the read stream irp */
498c2c66affSColin Finck         Status = KsProbeStreamIrp(Irp, KSPROBE_STREAMREAD | KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK, Length);
499c2c66affSColin Finck     }
500c2c66affSColin Finck 
501c2c66affSColin Finck     if (!NT_SUCCESS(Status))
502c2c66affSColin Finck     {
503c2c66affSColin Finck         DPRINT1("KsProbeStreamIrp failed with Status %x Cancel %u\n", Status, Irp->Cancel);
504c2c66affSColin Finck         Irp->MdlAddress = Mdl;
505c2c66affSColin Finck         FreeItem(Context);
506c2c66affSColin Finck         return SetIrpIoStatus(Irp, Status, 0);
507c2c66affSColin Finck     }
508c2c66affSColin Finck 
509c2c66affSColin Finck     /* get device info */
510c2c66affSColin Finck     DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer;
511c2c66affSColin Finck     ASSERT(DeviceInfo);
512c2c66affSColin Finck 
513c2c66affSColin Finck     /* now get sysaudio file object */
514c2c66affSColin Finck     Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
515c2c66affSColin Finck     if (!NT_SUCCESS(Status))
516c2c66affSColin Finck     {
517c2c66affSColin Finck         DPRINT1("Invalid pin handle %p\n", DeviceInfo->hDevice);
518c2c66affSColin Finck         Irp->MdlAddress = Mdl;
519c2c66affSColin Finck         FreeItem(Context);
520c2c66affSColin Finck         return SetIrpIoStatus(Irp, Status, 0);
521c2c66affSColin Finck     }
522c2c66affSColin Finck 
523c2c66affSColin Finck     /* store file object whose reference is released in the completion callback */
524c2c66affSColin Finck     Context->FileObject = FileObject;
525c2c66affSColin Finck 
526c2c66affSColin Finck     /* skip current irp stack location */
527c2c66affSColin Finck     IoSkipCurrentIrpStackLocation(Irp);
528c2c66affSColin Finck 
529c2c66affSColin Finck     /* get next stack location */
530c2c66affSColin Finck     IoStack = IoGetNextIrpStackLocation(Irp);
531c2c66affSColin Finck 
532c2c66affSColin Finck     /* prepare stack location */
533c2c66affSColin Finck     IoStack->FileObject = FileObject;
534c2c66affSColin Finck     IoStack->Parameters.Write.Length = Length;
535c2c66affSColin Finck     IoStack->MajorFunction = IRP_MJ_WRITE;
536c2c66affSColin Finck     IoStack->Parameters.DeviceIoControl.IoControlCode = (Read ? IOCTL_KS_READ_STREAM : IOCTL_KS_WRITE_STREAM);
537c2c66affSColin Finck     IoSetCompletionRoutine(Irp, IoCompletion, (PVOID)Context, TRUE, TRUE, TRUE);
538c2c66affSColin Finck 
539c2c66affSColin Finck     /* mark irp as pending */
540c2c66affSColin Finck //    IoMarkIrpPending(Irp);
541c2c66affSColin Finck     /* call the driver */
542c2c66affSColin Finck     Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
543c2c66affSColin Finck     return Status;
544c2c66affSColin Finck }
545