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
11 const GUID KSPROPSETID_Sysaudio
= {0xCBE3FAA0L
, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
15 IN PDEVICE_OBJECT DeviceObject
,
17 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
18 IN PWDMAUD_CLIENT ClientInfo
)
20 if (DeviceInfo
->DeviceType
== MIXER_DEVICE_TYPE
)
22 return WdmAudControlOpenMixer(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
25 if (DeviceInfo
->DeviceType
== WAVE_OUT_DEVICE_TYPE
|| DeviceInfo
->DeviceType
== WAVE_IN_DEVICE_TYPE
)
27 return WdmAudControlOpenWave(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
30 if (DeviceInfo
->DeviceType
== MIDI_OUT_DEVICE_TYPE
|| DeviceInfo
->DeviceType
== MIDI_IN_DEVICE_TYPE
)
32 return WdmAudControlOpenMidi(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
36 return SetIrpIoStatus(Irp
, STATUS_NOT_SUPPORTED
, sizeof(WDMAUD_DEVICE_INFO
));
40 WdmAudControlDeviceType(
41 IN PDEVICE_OBJECT DeviceObject
,
43 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
44 IN PWDMAUD_CLIENT ClientInfo
)
47 NTSTATUS Status
= STATUS_SUCCESS
;
48 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
50 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
52 if (DeviceInfo
->DeviceType
== MIXER_DEVICE_TYPE
)
54 Result
= WdmAudGetMixerDeviceCount();
56 else if (DeviceInfo
->DeviceType
== WAVE_OUT_DEVICE_TYPE
)
58 Result
= WdmAudGetWaveInDeviceCount();
60 else if (DeviceInfo
->DeviceType
== WAVE_IN_DEVICE_TYPE
)
62 Result
= WdmAudGetWaveOutDeviceCount();
64 else if (DeviceInfo
->DeviceType
== MIDI_IN_DEVICE_TYPE
)
66 Result
= WdmAudGetMidiInDeviceCount();
68 else if (DeviceInfo
->DeviceType
== MIDI_OUT_DEVICE_TYPE
)
70 Result
= WdmAudGetMidiOutDeviceCount();
74 /* store result count */
75 DeviceInfo
->DeviceCount
= Result
;
77 DPRINT("WdmAudControlDeviceType Status %x Devices %u\n", Status
, DeviceInfo
->DeviceCount
);
78 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
82 WdmAudControlDeviceState(
83 IN PDEVICE_OBJECT DeviceObject
,
85 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
86 IN PWDMAUD_CLIENT ClientInfo
)
92 PFILE_OBJECT FileObject
;
94 DPRINT("WdmAudControlDeviceState\n");
96 Status
= ObReferenceObjectByHandle(DeviceInfo
->hDevice
, GENERIC_READ
| GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
97 if (!NT_SUCCESS(Status
))
99 DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo
->hDevice
, DeviceInfo
->DeviceType
);
100 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
103 Property
.Set
= KSPROPSETID_Connection
;
104 Property
.Id
= KSPROPERTY_CONNECTION_STATE
;
105 Property
.Flags
= KSPROPERTY_TYPE_SET
;
107 State
= DeviceInfo
->u
.State
;
109 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), (PVOID
)&State
, sizeof(KSSTATE
), &BytesReturned
);
111 ObDereferenceObject(FileObject
);
113 DPRINT("WdmAudControlDeviceState Status %x\n", Status
);
114 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
119 IN PDEVICE_OBJECT DeviceObject
,
121 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
122 IN PWDMAUD_CLIENT ClientInfo
)
124 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
125 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
127 DPRINT("WdmAudCapabilities entered\n");
129 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
131 if (DeviceInfo
->DeviceType
== MIXER_DEVICE_TYPE
)
133 Status
= WdmAudMixerCapabilities(DeviceObject
, DeviceInfo
, ClientInfo
, DeviceExtension
);
135 else if (DeviceInfo
->DeviceType
== WAVE_IN_DEVICE_TYPE
|| DeviceInfo
->DeviceType
== WAVE_OUT_DEVICE_TYPE
)
137 Status
= WdmAudWaveCapabilities(DeviceObject
, DeviceInfo
, ClientInfo
, DeviceExtension
);
139 else if (DeviceInfo
->DeviceType
== MIDI_IN_DEVICE_TYPE
|| DeviceInfo
->DeviceType
== MIDI_OUT_DEVICE_TYPE
)
141 Status
= WdmAudMidiCapabilities(DeviceObject
, DeviceInfo
, ClientInfo
, DeviceExtension
);
144 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
150 IN PDEVICE_OBJECT DeviceObject
,
152 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
153 IN PWDMAUD_CLIENT ClientInfo
)
157 for(Index
= 0; Index
< ClientInfo
->NumPins
; Index
++)
159 if (ClientInfo
->hPins
[Index
].Handle
== DeviceInfo
->hDevice
&& ClientInfo
->hPins
[Index
].Type
!= MIXER_DEVICE_TYPE
)
161 DPRINT1("Closing device %p\n", DeviceInfo
->hDevice
);
162 ZwClose(DeviceInfo
->hDevice
);
163 ClientInfo
->hPins
[Index
].Handle
= NULL
;
164 SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
165 return STATUS_SUCCESS
;
167 else if (ClientInfo
->hPins
[Index
].Handle
== DeviceInfo
->hDevice
&& ClientInfo
->hPins
[Index
].Type
== MIXER_DEVICE_TYPE
)
169 if (ClientInfo
->hPins
[Index
].NotifyEvent
)
171 ObDereferenceObject(ClientInfo
->hPins
[Index
].NotifyEvent
);
172 ClientInfo
->hPins
[Index
].NotifyEvent
= NULL
;
177 SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, sizeof(WDMAUD_DEVICE_INFO
));
178 return STATUS_INVALID_PARAMETER
;
184 IN PDEVICE_OBJECT DeviceObject
,
186 IN PWDMAUD_DEVICE_INFO DeviceInfo
,
187 IN PWDMAUD_CLIENT ClientInfo
)
189 PFILE_OBJECT FileObject
;
192 KSALLOCATOR_FRAMING Framing
;
195 /* Get sysaudio pin file object */
196 Status
= ObReferenceObjectByHandle(DeviceInfo
->hDevice
, GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
197 if (!NT_SUCCESS(Status
))
199 DPRINT1("Invalid buffer handle %p\n", DeviceInfo
->hDevice
);
200 return SetIrpIoStatus(Irp
, Status
, 0);
203 /* Setup get framing request */
204 Property
.Id
= KSPROPERTY_CONNECTION_ALLOCATORFRAMING
;
205 Property
.Flags
= KSPROPERTY_TYPE_GET
;
206 Property
.Set
= KSPROPSETID_Connection
;
208 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), (PVOID
)&Framing
, sizeof(KSALLOCATOR_FRAMING
), &BytesReturned
);
210 if (NT_SUCCESS(Status
))
212 /* Store framesize */
213 DeviceInfo
->u
.FrameSize
= Framing
.FrameSize
;
216 /* Release file object */
217 ObDereferenceObject(FileObject
);
219 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
225 WdmAudGetDeviceInterface(
226 IN PDEVICE_OBJECT DeviceObject
,
228 IN PWDMAUD_DEVICE_INFO DeviceInfo
)
230 PWDMAUD_DEVICE_EXTENSION DeviceExtension
;
235 /* get device extension */
236 DeviceExtension
= (PWDMAUD_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
238 /* get device interface string input length */
239 Size
= DeviceInfo
->u
.Interface
.DeviceInterfaceStringSize
;
242 Status
= WdmAudGetPnpNameByIndexAndType(DeviceInfo
->DeviceIndex
, DeviceInfo
->DeviceType
, &Device
);
244 /* check for success */
245 if (!NT_SUCCESS(Status
))
247 /* invalid device id */
248 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
251 /* calculate length */
252 Length
= (wcslen(Device
)+1) * sizeof(WCHAR
);
256 /* store device interface size */
257 DeviceInfo
->u
.Interface
.DeviceInterfaceStringSize
= Length
;
259 else if (Size
< Length
)
261 /* buffer too small */
262 DeviceInfo
->u
.Interface
.DeviceInterfaceStringSize
= Length
;
263 return SetIrpIoStatus(Irp
, STATUS_BUFFER_OVERFLOW
, sizeof(WDMAUD_DEVICE_INFO
));
268 RtlMoveMemory(DeviceInfo
->u
.Interface
.DeviceInterfaceString
, Device
, Length
);
272 return SetIrpIoStatus(Irp
, STATUS_SUCCESS
, sizeof(WDMAUD_DEVICE_INFO
));
278 IN PDEVICE_OBJECT DeviceObject
,
280 IN PWDMAUD_DEVICE_INFO DeviceInfo
)
285 PFILE_OBJECT FileObject
;
287 DPRINT("WdmAudResetStream\n");
289 Status
= ObReferenceObjectByHandle(DeviceInfo
->hDevice
, GENERIC_READ
| GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
290 if (!NT_SUCCESS(Status
))
292 DPRINT1("Error: invalid device handle provided %p Type %x\n", DeviceInfo
->hDevice
, DeviceInfo
->DeviceType
);
293 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
296 ResetStream
= DeviceInfo
->u
.ResetStream
;
297 ASSERT(ResetStream
== KSRESET_BEGIN
|| ResetStream
== KSRESET_END
);
299 Status
= KsSynchronousIoControlDevice(FileObject
, KernelMode
, IOCTL_KS_RESET_STATE
, (PVOID
)&ResetStream
, sizeof(KSRESET
), NULL
, 0, &BytesReturned
);
301 ObDereferenceObject(FileObject
);
303 DPRINT("WdmAudResetStream Status %x\n", Status
);
304 return SetIrpIoStatus(Irp
, Status
, sizeof(WDMAUD_DEVICE_INFO
));
310 IN PDEVICE_OBJECT DeviceObject
,
313 PIO_STACK_LOCATION IoStack
;
314 PWDMAUD_DEVICE_INFO DeviceInfo
;
315 PWDMAUD_CLIENT ClientInfo
;
317 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
319 DPRINT("WdmAudDeviceControl entered\n");
321 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(WDMAUD_DEVICE_INFO
))
323 /* invalid parameter */
324 DPRINT1("Input buffer too small size %u expected %u\n", IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
, sizeof(WDMAUD_DEVICE_INFO
));
325 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
328 DeviceInfo
= (PWDMAUD_DEVICE_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
330 if (DeviceInfo
->DeviceType
< MIN_SOUND_DEVICE_TYPE
|| DeviceInfo
->DeviceType
> MAX_SOUND_DEVICE_TYPE
)
332 /* invalid parameter */
333 DPRINT1("Error: device type not set\n");
334 return SetIrpIoStatus(Irp
, STATUS_INVALID_PARAMETER
, 0);
337 if (!IoStack
->FileObject
)
339 /* file object parameter */
340 DPRINT1("Error: file object is not attached\n");
341 return SetIrpIoStatus(Irp
, STATUS_UNSUCCESSFUL
, 0);
343 ClientInfo
= (PWDMAUD_CLIENT
)IoStack
->FileObject
->FsContext
;
345 DPRINT("WdmAudDeviceControl entered\n");
347 switch(IoStack
->Parameters
.DeviceIoControl
.IoControlCode
)
349 case IOCTL_OPEN_WDMAUD
:
350 return WdmAudControlOpen(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
351 case IOCTL_GETNUMDEVS_TYPE
:
352 return WdmAudControlDeviceType(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
353 case IOCTL_SETDEVICE_STATE
:
354 return WdmAudControlDeviceState(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
355 case IOCTL_GETCAPABILITIES
:
356 return WdmAudCapabilities(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
357 case IOCTL_CLOSE_WDMAUD
:
358 return WdmAudIoctlClose(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
359 case IOCTL_GETFRAMESIZE
:
360 return WdmAudFrameSize(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
361 case IOCTL_GETLINEINFO
:
362 return WdmAudGetLineInfo(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
363 case IOCTL_GETLINECONTROLS
:
364 return WdmAudGetLineControls(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
365 case IOCTL_SETCONTROLDETAILS
:
366 return WdmAudSetControlDetails(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
367 case IOCTL_GETCONTROLDETAILS
:
368 return WdmAudGetControlDetails(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
369 case IOCTL_QUERYDEVICEINTERFACESTRING
:
370 return WdmAudGetDeviceInterface(DeviceObject
, Irp
, DeviceInfo
);
371 case IOCTL_GET_MIXER_EVENT
:
372 return WdmAudGetMixerEvent(DeviceObject
, Irp
, DeviceInfo
, ClientInfo
);
373 case IOCTL_RESET_STREAM
:
374 return WdmAudResetStream(DeviceObject
, Irp
, DeviceInfo
);
377 case IOCTL_GETVOLUME
:
378 case IOCTL_SETVOLUME
:
380 DPRINT1("Unhandeled %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
384 return SetIrpIoStatus(Irp
, STATUS_NOT_IMPLEMENTED
, 0);
390 PDEVICE_OBJECT DeviceObject
,
394 PKSSTREAM_HEADER Header
;
397 PWDMAUD_COMPLETION_CONTEXT Context
= (PWDMAUD_COMPLETION_CONTEXT
)Ctx
;
399 /* get stream header */
400 Header
= (PKSSTREAM_HEADER
)Irp
->AssociatedIrp
.SystemBuffer
;
405 /* iterate through all stream headers and collect size */
408 if (Context
->Function
== IOCTL_KS_READ_STREAM
)
410 /* length is stored in DataUsed */
411 Length
+= Header
->DataUsed
;
415 /* length stored in frameextend */
416 Length
+= Header
->FrameExtent
;
420 Context
->Length
-= Header
->Size
;
422 /* move to next stream header */
423 Header
= (PKSSTREAM_HEADER
)((ULONG_PTR
)Header
+ Header
->Size
);
425 }while(Context
->Length
);
427 /* time to free all allocated mdls */
428 Mdl
= Irp
->MdlAddress
;
443 Irp
->MdlAddress
= NULL
;
445 /* check if mdl is locked */
446 if (Context
->Mdl
->MdlFlags
& MDL_PAGES_LOCKED
)
449 MmUnlockPages(Context
->Mdl
);
452 /* now free the mdl */
453 IoFreeMdl(Context
->Mdl
);
455 DPRINT("IoCompletion Irp %p IoStatus %lx Information %lx Length %lu\n", Irp
, Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
, Length
);
457 if (Irp
->IoStatus
.Status
== STATUS_SUCCESS
)
459 /* store the length */
460 Irp
->IoStatus
.Information
= Length
;
465 Irp
->IoStatus
.Information
= 0;
471 return STATUS_SUCCESS
;
478 IN PDEVICE_OBJECT DeviceObject
,
482 PWDMAUD_DEVICE_INFO DeviceInfo
;
483 PFILE_OBJECT FileObject
;
484 PIO_STACK_LOCATION IoStack
;
488 PWDMAUD_COMPLETION_CONTEXT Context
;
490 /* allocate completion context */
491 Context
= AllocateItem(NonPagedPool
, sizeof(WDMAUD_COMPLETION_CONTEXT
));
495 /* not enough memory */
496 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
497 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
500 return STATUS_INSUFFICIENT_RESOURCES
;
503 /* get current irp stack location */
504 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
506 /* store the input buffer in UserBuffer - as KsProbeStreamIrp operates on IRP_MJ_DEVICE_CONTROL */
507 Irp
->UserBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
510 ASSERT(Irp
->UserBuffer
);
512 /* get the length of the request length */
513 Length
= IoStack
->Parameters
.Write
.Length
;
515 /* store outputbuffer length */
516 IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
= Length
;
519 Context
->Length
= Length
;
520 Context
->Function
= (IoStack
->MajorFunction
== IRP_MJ_WRITE
? IOCTL_KS_WRITE_STREAM
: IOCTL_KS_READ_STREAM
);
521 Context
->Mdl
= Irp
->MdlAddress
;
523 /* store mdl address */
524 Mdl
= Irp
->MdlAddress
;
526 /* remove mdladdress as KsProbeStreamIrp will interprete it as an already probed audio buffer */
527 Irp
->MdlAddress
= NULL
;
529 /* check for success */
531 if (IoStack
->MajorFunction
== IRP_MJ_WRITE
)
533 /* probe the write stream irp */
535 Status
= KsProbeStreamIrp(Irp
, KSPROBE_STREAMWRITE
| KSPROBE_ALLOCATEMDL
| KSPROBE_PROBEANDLOCK
, Length
);
539 /* probe the read stream irp */
540 Status
= KsProbeStreamIrp(Irp
, KSPROBE_STREAMREAD
| KSPROBE_ALLOCATEMDL
| KSPROBE_PROBEANDLOCK
, Length
);
543 if (!NT_SUCCESS(Status
))
545 DPRINT1("KsProbeStreamIrp failed with Status %x Cancel %u\n", Status
, Irp
->Cancel
);
546 Irp
->MdlAddress
= Mdl
;
547 return SetIrpIoStatus(Irp
, Status
, 0);
550 /* get device info */
551 DeviceInfo
= (PWDMAUD_DEVICE_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
554 /* now get sysaudio file object */
555 Status
= ObReferenceObjectByHandle(DeviceInfo
->hDevice
, GENERIC_WRITE
, IoFileObjectType
, KernelMode
, (PVOID
*)&FileObject
, NULL
);
556 if (!NT_SUCCESS(Status
))
558 DPRINT1("Invalid pin handle %p\n", DeviceInfo
->hDevice
);
559 return SetIrpIoStatus(Irp
, Status
, 0);
562 /* skip current irp stack location */
563 IoSkipCurrentIrpStackLocation(Irp
);
565 /* get next stack location */
566 IoStack
= IoGetNextIrpStackLocation(Irp
);
570 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_KS_READ_STREAM
;
574 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_KS_WRITE_STREAM
;
577 /* attach file object */
578 IoStack
->FileObject
= FileObject
;
579 IoStack
->Parameters
.Write
.Length
= Length
;
580 IoStack
->MajorFunction
= IRP_MJ_WRITE
;
582 IoSetCompletionRoutine(Irp
, IoCompletion
, (PVOID
)Context
, TRUE
, TRUE
, TRUE
);
585 /* mark irp as pending */
586 // IoMarkIrpPending(Irp);
587 /* call the driver */
588 Status
= IoCallDriver(IoGetRelatedDeviceObject(FileObject
), Irp
);
590 /* dereference file object */
591 ObDereferenceObject(FileObject
);