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
15 const GUID KSPROPSETID_Sysaudio
= {0xCBE3FAA0L
, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
19 IN PDEVICE_OBJECT DeviceObject
,
21 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
22 IN PWDMAUD_CLIENT ClientInfo
)
24 if (DeviceInfo
->DeviceType
== MIXER_DEVICE_TYPE
)
26 return WdmAudControlOpenMixer(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
29 if (DeviceInfo
->DeviceType
== WAVE_OUT_DEVICE_TYPE
|| DeviceInfo
->DeviceType
== WAVE_IN_DEVICE_TYPE
)
31 return WdmAudControlOpenWave(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
34 if (DeviceInfo
->DeviceType
== MIDI_OUT_DEVICE_TYPE
|| DeviceInfo
->DeviceType
== MIDI_IN_DEVICE_TYPE
)
36 return WdmAudControlOpenMidi(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
40 return SetIrpIoStatus(Irp
, STATUS_NOT_SUPPORTED
, sizeof(WDMAUD_DEVICE_INFO
));
44 WdmAudControlDeviceType(
45 IN PDEVICE_OBJECT DeviceObject
,
47 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
48 IN PWDMAUD_CLIENT ClientInfo
)
51 NTSTATUS Status
= STATUS_SUCCESS
;
53 if (DeviceInfo
->DeviceType
== MIXER_DEVICE_TYPE
)
55 Result
= WdmAudGetMixerDeviceCount();
57 else if (DeviceInfo
->DeviceType
== WAVE_OUT_DEVICE_TYPE
)
59 Result
= WdmAudGetWaveInDeviceCount();
61 else if (DeviceInfo
->DeviceType
== WAVE_IN_DEVICE_TYPE
)
63 Result
= WdmAudGetWaveOutDeviceCount();
65 else if (DeviceInfo
->DeviceType
== MIDI_IN_DEVICE_TYPE
)
67 Result
= WdmAudGetMidiInDeviceCount();
69 else if (DeviceInfo
->DeviceType
== MIDI_OUT_DEVICE_TYPE
)
71 Result
= WdmAudGetMidiOutDeviceCount();
75 /* store result count */
76 DeviceInfo
->DeviceCount
= Result
;
78 DPRINT("WdmAudControlDeviceType Status %x Devices %u\n", Status
, DeviceInfo
->DeviceCount
);
79 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
83 WdmAudControlDeviceState(
84 IN PDEVICE_OBJECT DeviceObject
,
86 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
87 IN PWDMAUD_CLIENT ClientInfo
)
93 PFILE_OBJECT FileObject
;
95 DPRINT("WdmAudControlDeviceState\n");
97 Status
= ObReferenceObjectByHandle(DeviceInfo
->hDevice
, GENERIC_READ
| GENERIC_WRITE
, *IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
98 if (!NT_SUCCESS(Status
))
100 DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo
->hDevice
, DeviceInfo
->DeviceType
);
101 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
104 Property
.Set
= KSPROPSETID_Connection
;
105 Property
.Id
= KSPROPERTY_CONNECTION_STATE
;
106 Property
.Flags
= KSPROPERTY_TYPE_SET
;
108 State
= DeviceInfo
->u
.State
;
110 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), (PVOID
)&State
, sizeof(KSSTATE
), &BytesReturned
);
112 ObDereferenceObject(FileObject
);
114 DPRINT("WdmAudControlDeviceState Status %x\n", Status
);
115 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
120 IN PDEVICE_OBJECT DeviceObject
,
122 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
123 IN PWDMAUD_CLIENT ClientInfo
)
125 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
126 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
128 DPRINT("WdmAudCapabilities entered\n");
130 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
132 if (DeviceInfo
->DeviceType
== MIXER_DEVICE_TYPE
)
134 Status
= WdmAudMixerCapabilities(DeviceObject
, DeviceInfo
, ClientInfo
, DeviceExtension
);
136 else if (DeviceInfo
->DeviceType
== WAVE_IN_DEVICE_TYPE
|| DeviceInfo
->DeviceType
== WAVE_OUT_DEVICE_TYPE
)
138 Status
= WdmAudWaveCapabilities(DeviceObject
, DeviceInfo
, ClientInfo
, DeviceExtension
);
140 else if (DeviceInfo
->DeviceType
== MIDI_IN_DEVICE_TYPE
|| DeviceInfo
->DeviceType
== MIDI_OUT_DEVICE_TYPE
)
142 Status
= WdmAudMidiCapabilities(DeviceObject
, DeviceInfo
, ClientInfo
, DeviceExtension
);
145 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
151 IN PDEVICE_OBJECT DeviceObject
,
153 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
154 IN PWDMAUD_CLIENT ClientInfo
)
158 for(Index
= 0; Index
< ClientInfo
->NumPins
; Index
++)
160 if (ClientInfo
->hPins
[Index
].Handle
== DeviceInfo
->hDevice
&& ClientInfo
->hPins
[Index
].Type
!= MIXER_DEVICE_TYPE
)
162 DPRINT1("Closing device %p\n", DeviceInfo
->hDevice
);
163 ZwClose(DeviceInfo
->hDevice
);
164 ClientInfo
->hPins
[Index
].Handle
= NULL
;
165 SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
166 return STATUS_SUCCESS
;
168 else if (ClientInfo
->hPins
[Index
].Handle
== DeviceInfo
->hDevice
&& ClientInfo
->hPins
[Index
].Type
== MIXER_DEVICE_TYPE
)
170 if (ClientInfo
->hPins
[Index
].NotifyEvent
)
172 ObDereferenceObject(ClientInfo
->hPins
[Index
].NotifyEvent
);
173 ClientInfo
->hPins
[Index
].NotifyEvent
= NULL
;
178 SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, sizeof(WDMAUD_DEVICE_INFO
));
179 return STATUS_INVALID_PARAMETER
;
185 IN PDEVICE_OBJECT DeviceObject
,
187 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
188 IN PWDMAUD_CLIENT ClientInfo
)
190 PFILE_OBJECT FileObject
;
193 KSALLOCATOR_FRAMING Framing
;
196 /* Get sysaudio pin file object */
197 Status
= ObReferenceObjectByHandle(DeviceInfo
->hDevice
, GENERIC_WRITE
, *IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
198 if (!NT_SUCCESS(Status
))
200 DPRINT1("Invalid buffer handle %p\n", DeviceInfo
->hDevice
);
201 return SetIrpIoStatus(Irp
, Status
, 0);
204 /* Setup get framing request */
205 Property
.Id
= KSPROPERTY_CONNECTION_ALLOCATORFRAMING
;
206 Property
.Flags
= KSPROPERTY_TYPE_GET
;
207 Property
.Set
= KSPROPSETID_Connection
;
209 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), (PVOID
)&Framing
, sizeof(KSALLOCATOR_FRAMING
), &BytesReturned
);
211 if (NT_SUCCESS(Status
))
213 /* Store framesize */
214 DeviceInfo
->u
.FrameSize
= Framing
.FrameSize
;
217 /* Release file object */
218 ObDereferenceObject(FileObject
);
220 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
226 WdmAudGetDeviceInterface(
227 IN PDEVICE_OBJECT DeviceObject
,
229 IN PWDMAUD_DEVICE_INFO DeviceInfo
)
235 /* get device interface string input length */
236 Size
= DeviceInfo
->u
.Interface
.DeviceInterfaceStringSize
;
239 Status
= WdmAudGetPnpNameByIndexAndType(DeviceInfo
->DeviceIndex
, DeviceInfo
->DeviceType
, &Device
);
241 /* check for success */
242 if (!NT_SUCCESS(Status
))
244 /* invalid device id */
245 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
248 /* calculate length */
249 Length
= (wcslen(Device
)+1) * sizeof(WCHAR
);
253 /* store device interface size */
254 DeviceInfo
->u
.Interface
.DeviceInterfaceStringSize
= Length
;
256 else if (Size
< Length
)
258 /* buffer too small */
259 DeviceInfo
->u
.Interface
.DeviceInterfaceStringSize
= Length
;
260 return SetIrpIoStatus(Irp
, STATUS_BUFFER_OVERFLOW
, sizeof(WDMAUD_DEVICE_INFO
));
265 RtlMoveMemory(DeviceInfo
->u
.Interface
.DeviceInterfaceString
, Device
, Length
);
269 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
275 IN PDEVICE_OBJECT DeviceObject
,
277 IN PWDMAUD_DEVICE_INFO DeviceInfo
)
282 PFILE_OBJECT FileObject
;
284 DPRINT("WdmAudResetStream\n");
286 Status
= ObReferenceObjectByHandle(DeviceInfo
->hDevice
, GENERIC_READ
| GENERIC_WRITE
, *IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
287 if (!NT_SUCCESS(Status
))
289 DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo
->hDevice
, DeviceInfo
->DeviceType
);
290 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
293 ResetStream
= DeviceInfo
->u
.ResetStream
;
294 ASSERT(ResetStream
== KSRESET_BEGIN
|| ResetStream
== KSRESET_END
);
296 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_RESET_STATE
, (PVOID
)&ResetStream
, sizeof(KSRESET
), NULL
, 0, &BytesReturned
);
298 ObDereferenceObject(FileObject
);
300 DPRINT("WdmAudResetStream Status %x\n", Status
);
301 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
307 IN PDEVICE_OBJECT DeviceObject
,
310 PIO_STACK_LOCATION IoStack
;
311 PWDMAUD_DEVICE_INFO DeviceInfo
;
312 PWDMAUD_CLIENT ClientInfo
;
314 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
316 DPRINT("WdmAudDeviceControl entered\n");
318 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(WDMAUD_DEVICE_INFO
))
320 /* invalid parameter */
321 DPRINT1("Input buffer too small size %u expected %u\n", IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
, sizeof(WDMAUD_DEVICE_INFO
));
322 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
325 DeviceInfo
= (PWDMAUD_DEVICE_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
327 if (DeviceInfo
->DeviceType
< MIN_SOUND_DEVICE_TYPE
|| DeviceInfo
->DeviceType
> MAX_SOUND_DEVICE_TYPE
)
329 /* invalid parameter */
330 DPRINT1("Error: device type not set\n");
331 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
334 if (!IoStack
->FileObject
|| !IoStack
->FileObject
->FsContext
)
336 /* file object parameter */
337 DPRINT1("Error: file object is not attached\n");
338 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
340 ClientInfo
= (PWDMAUD_CLIENT
)IoStack
->FileObject
->FsContext
;
342 DPRINT("WdmAudDeviceControl entered\n");
344 switch(IoStack
->Parameters
.DeviceIoControl
.IoControlCode
)
346 case IOCTL_OPEN_WDMAUD
:
347 return WdmAudControlOpen(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
348 case IOCTL_GETNUMDEVS_TYPE
:
349 return WdmAudControlDeviceType(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
350 case IOCTL_SETDEVICE_STATE
:
351 return WdmAudControlDeviceState(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
352 case IOCTL_GETCAPABILITIES
:
353 return WdmAudCapabilities(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
354 case IOCTL_CLOSE_WDMAUD
:
355 return WdmAudIoctlClose(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
356 case IOCTL_GETFRAMESIZE
:
357 return WdmAudFrameSize(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
358 case IOCTL_GETLINEINFO
:
359 return WdmAudGetLineInfo(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
360 case IOCTL_GETLINECONTROLS
:
361 return WdmAudGetLineControls(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
362 case IOCTL_SETCONTROLDETAILS
:
363 return WdmAudSetControlDetails(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
364 case IOCTL_GETCONTROLDETAILS
:
365 return WdmAudGetControlDetails(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
366 case IOCTL_QUERYDEVICEINTERFACESTRING
:
367 return WdmAudGetDeviceInterface(DeviceObject
, Irp
, DeviceInfo
);
368 case IOCTL_GET_MIXER_EVENT
:
369 return WdmAudGetMixerEvent(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
370 case IOCTL_RESET_STREAM
:
371 return WdmAudResetStream(DeviceObject
, Irp
, DeviceInfo
);
374 case IOCTL_GETVOLUME
:
375 case IOCTL_SETVOLUME
:
377 DPRINT1("Unhandeled %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
381 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
387 PDEVICE_OBJECT DeviceObject
,
391 PKSSTREAM_HEADER Header
;
394 PWDMAUD_COMPLETION_CONTEXT Context
= (PWDMAUD_COMPLETION_CONTEXT
)Ctx
;
396 /* get stream header */
397 Header
= (PKSSTREAM_HEADER
)Irp
->AssociatedIrp
.SystemBuffer
;
402 /* time to free all allocated mdls */
403 Mdl
= Irp
->MdlAddress
;
418 Irp
->MdlAddress
= Context
->Mdl
;
422 DPRINT("IoCompletion Irp %p IoStatus %lx Information %lx Length %lu\n", Irp
, Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
, Length
);
424 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
427 Irp
->IoStatus
.Information
= 0;
430 /* dereference file object */
431 ObDereferenceObject(Context
->FileObject
);
436 return STATUS_SUCCESS
;
442 IN PDEVICE_OBJECT DeviceObject
,
446 PWDMAUD_DEVICE_INFO DeviceInfo
;
447 PFILE_OBJECT FileObject
;
448 PIO_STACK_LOCATION IoStack
;
452 PWDMAUD_COMPLETION_CONTEXT Context
;
454 /* allocate completion context */
455 Context
= AllocateItem(NonPagedPool
, sizeof(WDMAUD_COMPLETION_CONTEXT
));
459 /* not enough memory */
460 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
461 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
464 return STATUS_INSUFFICIENT_RESOURCES
;
467 /* get current irp stack location */
468 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
470 /* store the input buffer in UserBuffer - as KsProbeStreamIrp operates on IRP_MJ_DEVICE_CONTROL */
471 Irp
->UserBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
474 ASSERT(Irp
->UserBuffer
);
476 /* get the length of the request length */
477 Length
= IoStack
->Parameters
.Write
.Length
;
479 /* store outputbuffer length */
480 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= Length
;
483 Context
->Length
= Length
;
484 Context
->Function
= (IoStack
->MajorFunction
== IRP_MJ_WRITE
? IOCTL_KS_WRITE_STREAM
: IOCTL_KS_READ_STREAM
);
485 Context
->Mdl
= Irp
->MdlAddress
;
487 /* store mdl address */
488 Mdl
= Irp
->MdlAddress
;
490 /* remove mdladdress as KsProbeStreamIrp will interprete it as an already probed audio buffer */
491 Irp
->MdlAddress
= NULL
;
493 if (IoStack
->MajorFunction
== IRP_MJ_WRITE
)
495 /* probe the write stream irp */
497 Status
= KsProbeStreamIrp(Irp
, KSPROBE_STREAMWRITE
| KSPROBE_ALLOCATEMDL
| KSPROBE_PROBEANDLOCK
, Length
);
501 /* probe the read stream irp */
502 Status
= KsProbeStreamIrp(Irp
, KSPROBE_STREAMREAD
| KSPROBE_ALLOCATEMDL
| KSPROBE_PROBEANDLOCK
, Length
);
505 if (!NT_SUCCESS(Status
))
507 DPRINT1("KsProbeStreamIrp failed with Status %x Cancel %u\n", Status
, Irp
->Cancel
);
508 Irp
->MdlAddress
= Mdl
;
510 return SetIrpIoStatus(Irp
, Status
, 0);
513 /* get device info */
514 DeviceInfo
= (PWDMAUD_DEVICE_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
517 /* now get sysaudio file object */
518 Status
= ObReferenceObjectByHandle(DeviceInfo
->hDevice
, GENERIC_WRITE
, *IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
519 if (!NT_SUCCESS(Status
))
521 DPRINT1("Invalid pin handle %p\n", DeviceInfo
->hDevice
);
522 Irp
->MdlAddress
= Mdl
;
524 return SetIrpIoStatus(Irp
, Status
, 0);
527 /* store file object whose reference is released in the completion callback */
528 Context
->FileObject
= FileObject
;
530 /* skip current irp stack location */
531 IoSkipCurrentIrpStackLocation(Irp
);
533 /* get next stack location */
534 IoStack
= IoGetNextIrpStackLocation(Irp
);
536 /* prepare stack location */
537 IoStack
->FileObject
= FileObject
;
538 IoStack
->Parameters
.Write
.Length
= Length
;
539 IoStack
->MajorFunction
= IRP_MJ_WRITE
;
540 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= (Read
? IOCTL_KS_READ_STREAM
: IOCTL_KS_WRITE_STREAM
);
541 IoSetCompletionRoutine(Irp
, IoCompletion
, (PVOID
)Context
, TRUE
, TRUE
, TRUE
);
543 /* mark irp as pending */
544 // IoMarkIrpPending(Irp);
545 /* call the driver */
546 Status
= IoCallDriver(IoGetRelatedDeviceObject(FileObject
), Irp
);