3535 lines
118 KiB
C
3535 lines
118 KiB
C
/****************************************************************************
|
|
*
|
|
* ioctl.c
|
|
*
|
|
* DeviceIoControl communication interface between 32-bit wdmaud.drv
|
|
*
|
|
* Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
|
|
*
|
|
* History
|
|
* S.Mohanraj (MohanS)
|
|
* M.McLaughlin (MikeM)
|
|
* 5-19-97 - Noel Cross (NoelC)
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "wdmsys.h"
|
|
#include <devioctl.h>
|
|
|
|
extern ULONG gWavePreferredSysaudioDevice;
|
|
|
|
#pragma LOCKED_CODE
|
|
#pragma LOCKED_DATA
|
|
|
|
WDMAPENDINGIRP_QUEUE wdmaPendingIrpQueue;
|
|
|
|
#ifdef PROFILE
|
|
|
|
LIST_ENTRY WdmaAllocatedMdlListHead;
|
|
KSPIN_LOCK WdmaAllocatedMdlListSpinLock;
|
|
|
|
// Initialize the List Heads and Mutexes in order to track resources
|
|
VOID WdmaInitProfile()
|
|
{
|
|
InitializeListHead(&WdmaAllocatedMdlListHead);
|
|
KeInitializeSpinLock(&WdmaAllocatedMdlListSpinLock);
|
|
}
|
|
|
|
NTSTATUS AddMdlToList
|
|
(
|
|
PMDL pMdl,
|
|
PWDMACONTEXT pWdmaContext
|
|
)
|
|
{
|
|
PALLOCATED_MDL_LIST_ITEM pAllocatedMdlListItem = NULL;
|
|
NTSTATUS Status;
|
|
|
|
Status = AudioAllocateMemory_Fixed(sizeof(*pAllocatedMdlListItem),
|
|
TAG_AudM_MDL,
|
|
ZERO_FILL_MEMORY,
|
|
&pAllocatedMdlListItem);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
pAllocatedMdlListItem->pMdl = pMdl;
|
|
pAllocatedMdlListItem->pContext = pWdmaContext;
|
|
|
|
ExInterlockedInsertTailList(&WdmaAllocatedMdlListHead,
|
|
&pAllocatedMdlListItem->Next,
|
|
&WdmaAllocatedMdlListSpinLock);
|
|
}
|
|
|
|
RETURN( Status );
|
|
}
|
|
|
|
NTSTATUS RemoveMdlFromList
|
|
(
|
|
PMDL pMdl
|
|
)
|
|
{
|
|
PLIST_ENTRY ple;
|
|
PALLOCATED_MDL_LIST_ITEM pAllocatedMdlListItem;
|
|
KIRQL OldIrql;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
ExAcquireSpinLock(&WdmaAllocatedMdlListSpinLock, &OldIrql);
|
|
|
|
for(ple = WdmaAllocatedMdlListHead.Flink;
|
|
ple != &WdmaAllocatedMdlListHead;
|
|
ple = ple->Flink)
|
|
{
|
|
pAllocatedMdlListItem = CONTAINING_RECORD(ple, ALLOCATED_MDL_LIST_ITEM, Next);
|
|
|
|
if (pAllocatedMdlListItem->pMdl == pMdl)
|
|
{
|
|
RemoveEntryList(&pAllocatedMdlListItem->Next);
|
|
AudioFreeMemory(sizeof(*pAllocatedMdlListItem),&pAllocatedMdlListItem);
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ExReleaseSpinLock(&WdmaAllocatedMdlListSpinLock, OldIrql);
|
|
|
|
RETURN( Status );
|
|
}
|
|
#endif
|
|
|
|
VOID WdmaCsqInsertIrp
|
|
(
|
|
IN struct _IO_CSQ *Csq,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PWDMAPENDINGIRP_QUEUE PendingIrpQueue = CONTAINING_RECORD(Csq, WDMAPENDINGIRP_QUEUE, Csq);
|
|
|
|
InsertTailList(&PendingIrpQueue->WdmaPendingIrpListHead,
|
|
&Irp->Tail.Overlay.ListEntry);
|
|
}
|
|
|
|
VOID WdmaCsqRemoveIrp
|
|
(
|
|
IN PIO_CSQ Csq,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
|
|
}
|
|
|
|
PIRP WdmaCsqPeekNextIrp
|
|
(
|
|
IN PIO_CSQ Csq,
|
|
IN PIRP Irp,
|
|
IN PVOID PeekContext
|
|
)
|
|
{
|
|
PWDMAPENDINGIRP_QUEUE PendingIrpQueue = CONTAINING_RECORD(Csq, WDMAPENDINGIRP_QUEUE, Csq);
|
|
PIRP nextIrp;
|
|
PLIST_ENTRY listEntry;
|
|
|
|
if (Irp == NULL) {
|
|
listEntry = PendingIrpQueue->WdmaPendingIrpListHead.Flink;
|
|
if (listEntry == &PendingIrpQueue->WdmaPendingIrpListHead) {
|
|
DPF(DL_TRACE|FA_IOCTL, ("Irp is NULL, queue is empty"));
|
|
return NULL;
|
|
}
|
|
|
|
nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
|
|
DPF(DL_TRACE|FA_IOCTL, ("Irp is NULL, nextIrp %x", nextIrp));
|
|
return nextIrp;
|
|
}
|
|
|
|
listEntry = Irp->Tail.Overlay.ListEntry.Flink;
|
|
|
|
|
|
//
|
|
// Enumerated to end of queue.
|
|
//
|
|
|
|
if (listEntry == &PendingIrpQueue->WdmaPendingIrpListHead) {
|
|
DPF(DL_TRACE|FA_IOCTL, ("End of queue reached Irp %x", Irp));
|
|
return NULL;
|
|
}
|
|
|
|
|
|
nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
|
|
return nextIrp;
|
|
}
|
|
|
|
VOID WdmaCsqAcquireLock
|
|
(
|
|
IN PIO_CSQ Csq,
|
|
OUT PKIRQL Irql
|
|
)
|
|
{
|
|
PWDMAPENDINGIRP_QUEUE PendingIrpQueue = CONTAINING_RECORD(Csq, WDMAPENDINGIRP_QUEUE, Csq);
|
|
KeAcquireSpinLock(&PendingIrpQueue->WdmaPendingIrpListSpinLock, Irql);
|
|
}
|
|
|
|
VOID WdmaCsqReleaseLock
|
|
(
|
|
IN PIO_CSQ Csq,
|
|
IN KIRQL Irql
|
|
)
|
|
{
|
|
PWDMAPENDINGIRP_QUEUE PendingIrpQueue = CONTAINING_RECORD(Csq, WDMAPENDINGIRP_QUEUE, Csq);
|
|
KeReleaseSpinLock(&PendingIrpQueue->WdmaPendingIrpListSpinLock, Irql);
|
|
}
|
|
|
|
VOID WdmaCsqCompleteCanceledIrp
|
|
(
|
|
IN PIO_CSQ pCsq,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
NTSTATUS AddIrpToPendingList
|
|
(
|
|
PIRP pIrp,
|
|
ULONG IrpDeviceType,
|
|
PWDMACONTEXT pWdmaContext,
|
|
PWDMAPENDINGIRP_CONTEXT *ppPendingIrpContext
|
|
)
|
|
{
|
|
PWDMAPENDINGIRP_CONTEXT pPendingIrpContext = NULL;
|
|
NTSTATUS Status;
|
|
|
|
Status = AudioAllocateMemory_Fixed(sizeof(*pPendingIrpContext),
|
|
TAG_AudR_IRP,
|
|
ZERO_FILL_MEMORY,
|
|
&pPendingIrpContext);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*ppPendingIrpContext = pPendingIrpContext;
|
|
|
|
pPendingIrpContext->IrpDeviceType = IrpDeviceType;
|
|
pPendingIrpContext->pContext = pWdmaContext;
|
|
|
|
IoCsqInsertIrp(&wdmaPendingIrpQueue.Csq,
|
|
pIrp,
|
|
&pPendingIrpContext->IrpContext);
|
|
}
|
|
|
|
RETURN( Status );
|
|
}
|
|
|
|
NTSTATUS RemoveIrpFromPendingList
|
|
(
|
|
PWDMAPENDINGIRP_CONTEXT pPendingIrpContext
|
|
)
|
|
{
|
|
PIO_CSQ_IRP_CONTEXT irpContext = &(pPendingIrpContext->IrpContext);
|
|
PIRP Irp;
|
|
NTSTATUS Status;
|
|
|
|
Irp = IoCsqRemoveIrp(&wdmaPendingIrpQueue.Csq, irpContext);
|
|
if (Irp) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
AudioFreeMemory(sizeof(*pPendingIrpContext),&irpContext);
|
|
|
|
RETURN( Status );
|
|
}
|
|
|
|
/****************************************************************************
|
|
* @doc INTERNAL
|
|
*
|
|
* @api BOOL | IsSysaudioInterfaceActive | Checks to see if the sysaudio
|
|
* device interface is active.
|
|
*
|
|
* @rdesc returns TRUE if sysaudio has been found, otherwise FALSE
|
|
***************************************************************************/
|
|
BOOL IsSysaudioInterfaceActive()
|
|
{
|
|
NTSTATUS Status;
|
|
PWSTR pwstrSymbolicLinkList = NULL;
|
|
BOOL bRet = FALSE;
|
|
|
|
Status = IoGetDeviceInterfaces(
|
|
&KSCATEGORY_SYSAUDIO,
|
|
NULL,
|
|
0,
|
|
&pwstrSymbolicLinkList);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (*pwstrSymbolicLinkList != UNICODE_NULL)
|
|
{
|
|
DPF(DL_TRACE|FA_IOCTL, ("yes"));
|
|
bRet = TRUE;
|
|
}
|
|
AudioFreeMemory_Unknown(&pwstrSymbolicLinkList);
|
|
} else {
|
|
DPF(DL_WARNING|FA_IOCTL,("IoGetDeviceInterface failed Statue=%08X",Status) );
|
|
}
|
|
|
|
DPF(DL_TRACE|FA_IOCTL, ("No"));
|
|
return bRet;
|
|
}
|
|
|
|
PVOID
|
|
GetSystemAddressForMdlWithFailFlag
|
|
(
|
|
PMDL pMdl
|
|
)
|
|
{
|
|
PVOID pAddress;
|
|
CSHORT OldFlags;
|
|
|
|
OldFlags = (pMdl->MdlFlags & MDL_MAPPING_CAN_FAIL);
|
|
pMdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
|
|
|
|
pAddress = MmGetSystemAddressForMdl( pMdl ) ;
|
|
|
|
pMdl->MdlFlags &= ~(MDL_MAPPING_CAN_FAIL);
|
|
pMdl->MdlFlags |= OldFlags;
|
|
|
|
return pAddress;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* @doc INTERNAL
|
|
*
|
|
* @api VOID | wdmaudMapBuffer | Allocates an MDL and returns a system address
|
|
* mapped pointer to the passed in buffer.
|
|
*
|
|
* @rdesc returns nothing
|
|
***************************************************************************/
|
|
VOID wdmaudMapBuffer
|
|
(
|
|
IN PIRP pIrp,
|
|
IN PVOID DataBuffer,
|
|
IN DWORD DataBufferSize,
|
|
OUT PVOID *ppMappedBuffer,
|
|
OUT PMDL *ppMdl,
|
|
IN PWDMACONTEXT pContext,
|
|
IN BOOL bWrite
|
|
)
|
|
{
|
|
NTSTATUS ListAddStatus = STATUS_UNSUCCESSFUL;
|
|
|
|
// Make sure that these are initialized to NULL
|
|
*ppMdl = NULL;
|
|
*ppMappedBuffer = NULL;
|
|
|
|
if (DataBuffer)
|
|
{
|
|
if (DataBufferSize)
|
|
{
|
|
*ppMdl = MmCreateMdl( NULL,
|
|
DataBuffer,
|
|
DataBufferSize );
|
|
if (*ppMdl)
|
|
{
|
|
try
|
|
{
|
|
MmProbeAndLockPages( *ppMdl,
|
|
pIrp->RequestorMode,
|
|
bWrite ? IoWriteAccess:IoReadAccess );
|
|
|
|
*ppMappedBuffer = GetSystemAddressForMdlWithFailFlag( *ppMdl ) ;
|
|
|
|
ListAddStatus = AddMdlToList(*ppMdl, pContext);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
if (NT_SUCCESS(ListAddStatus))
|
|
{
|
|
RemoveMdlFromList( *ppMdl );
|
|
}
|
|
IoFreeMdl( *ppMdl );
|
|
*ppMdl = NULL;
|
|
*ppMappedBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Must have failed in GetSystemAddressForMdlWithFailFlag, but since we set the
|
|
// MDL_MAPPING_CAN_FAIL flag our exception handler won't get executed. Do the
|
|
// cleanup here for the MDL creation.
|
|
//
|
|
if (NULL == *ppMappedBuffer)
|
|
{
|
|
if (NT_SUCCESS(ListAddStatus))
|
|
{
|
|
RemoveMdlFromList( *ppMdl );
|
|
}
|
|
|
|
if (*ppMdl)
|
|
{
|
|
MmUnlockPages(*ppMdl);
|
|
IoFreeMdl( *ppMdl );
|
|
*ppMdl = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* @doc INTERNAL
|
|
*
|
|
* @api VOID | wdmaudUnmapBuffer | Frees the MDL allocated by wdmaudMapBuffer
|
|
*
|
|
* @parm PMDL | pMdl | Pointer to the MDL to free.
|
|
*
|
|
* @rdesc returns nothing
|
|
***************************************************************************/
|
|
VOID wdmaudUnmapBuffer
|
|
(
|
|
PMDL pMdl
|
|
)
|
|
{
|
|
if (pMdl)
|
|
{
|
|
RemoveMdlFromList(pMdl);
|
|
|
|
MmUnlockPages(pMdl);
|
|
IoFreeMdl(pMdl);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
CaptureBufferToLocalPool(
|
|
PVOID DataBuffer,
|
|
DWORD DataBufferSize,
|
|
PVOID *ppMappedBuffer
|
|
#ifdef _WIN64
|
|
,DWORD ThunkBufferSize
|
|
#endif
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
DWORD CopySize=DataBufferSize;
|
|
|
|
#ifdef _WIN64
|
|
if (ThunkBufferSize) {
|
|
DataBufferSize=ThunkBufferSize;
|
|
ASSERT( DataBufferSize >= CopySize );
|
|
}
|
|
#endif
|
|
|
|
if (DataBufferSize)
|
|
{
|
|
Status = AudioAllocateMemory_Fixed(DataBufferSize,
|
|
TAG_AudB_BUFFER,
|
|
ZERO_FILL_MEMORY,
|
|
ppMappedBuffer);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
// Wrap around a try/except because the user mode memory
|
|
// might have been removed from underneath us.
|
|
try
|
|
{
|
|
RtlCopyMemory( *ppMappedBuffer,
|
|
DataBuffer,
|
|
CopySize);
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
AudioFreeMemory(DataBufferSize,ppMappedBuffer);
|
|
Status = GetExceptionCode();
|
|
}
|
|
}
|
|
}
|
|
|
|
RETURN( Status );
|
|
}
|
|
|
|
NTSTATUS
|
|
CopyAndFreeCapturedBuffer(
|
|
PVOID DataBuffer,
|
|
DWORD DataBufferSize,
|
|
PVOID *ppMappedBuffer
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
ASSERT(DataBuffer);
|
|
|
|
if (*ppMappedBuffer)
|
|
{
|
|
// Wrap around a try/except because the user mode memory
|
|
// might have been removed from underneath us.
|
|
try
|
|
{
|
|
RtlCopyMemory( DataBuffer,
|
|
*ppMappedBuffer,
|
|
DataBufferSize);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
AudioFreeMemory_Unknown(ppMappedBuffer);
|
|
}
|
|
|
|
RETURN( Status );
|
|
}
|
|
|
|
#pragma PAGEABLE_CODE
|
|
#pragma PAGEABLE_DATA
|
|
|
|
NTSTATUS
|
|
SoundDispatchCreate(
|
|
IN PDEVICE_OBJECT pDO,
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
PWDMACONTEXT pContext = NULL;
|
|
NTSTATUS Status;
|
|
int i;
|
|
|
|
PAGED_CODE();
|
|
DPF(DL_TRACE|FA_IOCTL, ("IRP_MJ_CREATE"));
|
|
|
|
Status = KsReferenceSoftwareBusObject(((PDEVICE_INSTANCE)pDO->DeviceExtension)->pDeviceHeader );
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
RETURN( Status );
|
|
}
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
Status = AudioAllocateMemory_Fixed(sizeof(*pContext),
|
|
TAG_Audx_CONTEXT,
|
|
ZERO_FILL_MEMORY,
|
|
&pContext);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
pIrpStack->FileObject->FsContext = pContext;
|
|
|
|
//
|
|
// Initialize out all the winmm device data structures.
|
|
//
|
|
#ifdef DEBUG
|
|
pContext->dwSig=CONTEXT_SIGNATURE;
|
|
#endif
|
|
|
|
pContext->VirtualWavePinId = MAXULONG;
|
|
pContext->VirtualMidiPinId = MAXULONG;
|
|
pContext->VirtualCDPinId = MAXULONG;
|
|
|
|
pContext->PreferredSysaudioWaveDevice = gWavePreferredSysaudioDevice;
|
|
|
|
if ( IsSysaudioInterfaceActive() )
|
|
{
|
|
pContext->pFileObjectSysaudio = kmxlOpenSysAudio();
|
|
} else {
|
|
DPF(DL_WARNING|FA_SYSAUDIO,("sysaudio not available") );
|
|
}
|
|
|
|
for (i = 0; i < MAXNUMDEVS; i++)
|
|
{
|
|
pContext->WaveOutDevs[i].pWdmaContext = pContext;
|
|
pContext->WaveInDevs[i].pWdmaContext = pContext;
|
|
pContext->MidiOutDevs[i].pWdmaContext = pContext;
|
|
pContext->MidiInDevs[i].pWdmaContext = pContext;
|
|
pContext->MixerDevs[i].pWdmaContext = pContext;
|
|
pContext->AuxDevs[i].pWdmaContext = pContext;
|
|
|
|
pContext->WaveOutDevs[i].Device = UNUSED_DEVICE;
|
|
pContext->WaveInDevs[i].Device = UNUSED_DEVICE;
|
|
pContext->MidiOutDevs[i].Device = UNUSED_DEVICE;
|
|
pContext->MidiInDevs[i].Device = UNUSED_DEVICE;
|
|
pContext->MixerDevs[i].Device = UNUSED_DEVICE;
|
|
pContext->AuxDevs[i].Device = UNUSED_DEVICE;
|
|
#ifdef DEBUG
|
|
pContext->MixerDevs[i].dwSig = MIXERDEVICE_SIGNATURE;
|
|
#endif
|
|
|
|
DPFASSERT(pContext->WaveOutDevs[i].pWavePin == NULL);
|
|
|
|
pContext->apCommonDevice[WaveInDevice][i] = (PCOMMONDEVICE)&pContext->WaveInDevs[i];
|
|
pContext->apCommonDevice[WaveOutDevice][i] = (PCOMMONDEVICE)&pContext->WaveOutDevs[i];
|
|
pContext->apCommonDevice[MidiInDevice][i] = (PCOMMONDEVICE)&pContext->MidiInDevs[i];
|
|
pContext->apCommonDevice[MidiOutDevice][i] = (PCOMMONDEVICE)&pContext->MidiOutDevs[i];
|
|
pContext->apCommonDevice[MixerDevice][i] = (PCOMMONDEVICE)&pContext->MixerDevs[i];
|
|
pContext->apCommonDevice[AuxDevice][i] = (PCOMMONDEVICE)&pContext->AuxDevs[i];
|
|
}
|
|
|
|
InitializeListHead(&pContext->DevNodeListHead);
|
|
pContext->DevNodeListCount = 0;
|
|
InitializeListHead(&pContext->WorkListHead);
|
|
KeInitializeSpinLock(&pContext->WorkListSpinLock);
|
|
ExInitializeWorkItem(&pContext->WorkListWorkItem, WorkListWorker, pContext);
|
|
|
|
ExInitializeWorkItem(&pContext->SysaudioWorkItem, SysaudioAddRemove, pContext);
|
|
|
|
KeInitializeEvent(&pContext->InitializedSysaudioEvent, NotificationEvent, FALSE);
|
|
|
|
Status = KsRegisterWorker( DelayedWorkQueue, &pContext->WorkListWorkerObject );
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = KsRegisterWorker( DelayedWorkQueue, &pContext->SysaudioWorkerObject );
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = IoRegisterPlugPlayNotification(
|
|
EventCategoryDeviceInterfaceChange,
|
|
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
|
|
(GUID *)&KSCATEGORY_SYSAUDIO,
|
|
pIrpStack->DeviceObject->DriverObject,
|
|
SysAudioPnPNotification,
|
|
pContext,
|
|
&pContext->NotificationEntry);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
AddFsContextToList(pContext);
|
|
DPF(DL_TRACE|FA_IOCTL, ("New pContext=%08Xh", pContext) );
|
|
}
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
KsUnregisterWorker( pContext->SysaudioWorkerObject );
|
|
pContext->SysaudioWorkerObject = NULL;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
KsUnregisterWorker( pContext->WorkListWorkerObject );
|
|
pContext->WorkListWorkerObject = NULL;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
AudioFreeMemory(sizeof(*pContext),&pContext);
|
|
pIrpStack->FileObject->FsContext = NULL;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
KsDereferenceSoftwareBusObject(((PDEVICE_INSTANCE)pDO->DeviceExtension)->pDeviceHeader );
|
|
}
|
|
|
|
pIrp->IoStatus.Status = Status;
|
|
pIrp->IoStatus.Information = 0;
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
|
|
RETURN( Status );
|
|
}
|
|
|
|
NTSTATUS
|
|
SoundDispatchClose(
|
|
IN PDEVICE_OBJECT pDO,
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
PKSWORKER WorkListWorkerObject;
|
|
PKSWORKER SysaudioWorkerObject;
|
|
PWDMACONTEXT pContext;
|
|
|
|
PAGED_CODE();
|
|
DPF(DL_TRACE|FA_IOCTL, ("IRP_MJ_CLOSE"));
|
|
//
|
|
// This routine is serialized by the i/o subsystem so there is no need to grab the
|
|
// mutex for protection. Furthermore, it is not possible to release the mutex
|
|
// after UninitializeSysaudio is called.
|
|
//
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
//
|
|
// Can't assume that FsContext is initialized if the device has
|
|
// been opened with FO_DIRECT_DEVICE_OPEN
|
|
//
|
|
if (pIrpStack->FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
|
|
{
|
|
DPF(DL_TRACE|FA_IOCTL, ("Opened with FO_DIRECT_DEVICE_OPEN, no device context") );
|
|
goto exit;
|
|
}
|
|
|
|
pContext = pIrpStack->FileObject->FsContext;
|
|
ASSERT(pContext);
|
|
|
|
DPF(DL_TRACE|FA_IOCTL, ("pWdmaContext=%08Xh", pContext) );
|
|
|
|
if (pContext->NotificationEntry != NULL)
|
|
{
|
|
IoUnregisterPlugPlayNotification(pContext->NotificationEntry);
|
|
pContext->NotificationEntry = NULL;
|
|
}
|
|
|
|
//
|
|
// force turds to be freed for a particular context
|
|
//
|
|
WdmaGrabMutex(pContext);
|
|
|
|
CleanupWaveDevices(pContext);
|
|
CleanupMidiDevices(pContext);
|
|
WdmaContextCleanup(pContext);
|
|
UninitializeSysaudio(pContext);
|
|
|
|
WorkListWorkerObject = pContext->WorkListWorkerObject;
|
|
pContext->WorkListWorkerObject = NULL;
|
|
|
|
SysaudioWorkerObject = pContext->SysaudioWorkerObject;
|
|
pContext->SysaudioWorkerObject = NULL;
|
|
|
|
WdmaReleaseMutex(pContext);
|
|
|
|
if (WorkListWorkerObject != NULL)
|
|
{
|
|
KsUnregisterWorker( WorkListWorkerObject );
|
|
}
|
|
|
|
if (SysaudioWorkerObject != NULL)
|
|
{
|
|
KsUnregisterWorker( SysaudioWorkerObject );
|
|
}
|
|
RemoveFsContextFromList(pContext);
|
|
|
|
//
|
|
// Workitem: Shouldn't WdmaReleaseMutex(pContext) be here rather then above?
|
|
// I would think that if we release the mutex before cleanly getting throug the
|
|
// cleanup we could have reentrancy problems. ???
|
|
//
|
|
// Also, note that all of pContext will be invalid after this AudioFreeMemory call!
|
|
//
|
|
kmxlRemoveContextFromNoteList(pContext);
|
|
|
|
if( pContext->pFileObjectSysaudio )
|
|
{
|
|
kmxlCloseSysAudio(pContext->pFileObjectSysaudio);
|
|
pContext->pFileObjectSysaudio = NULL;
|
|
}
|
|
|
|
AudioFreeMemory(sizeof(*pContext),&pContext);
|
|
pIrpStack->FileObject->FsContext = NULL;
|
|
|
|
exit:
|
|
KsDereferenceSoftwareBusObject(((PDEVICE_INSTANCE)pDO->DeviceExtension)->pDeviceHeader );
|
|
|
|
pIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
pIrp->IoStatus.Information = 0;
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SoundDispatchCleanup(
|
|
IN PDEVICE_OBJECT pDO,
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
PWDMACONTEXT pContext;
|
|
|
|
PAGED_CODE();
|
|
DPF(DL_TRACE|FA_IOCTL, ("IRP_MJ_CLEANUP"));
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
//
|
|
// Can't assume that FsContext is initialized if the device has
|
|
// been opened with FO_DIRECT_DEVICE_OPEN
|
|
//
|
|
if (pIrpStack->FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
|
|
{
|
|
DPF(DL_TRACE|FA_IOCTL, ("Opened with FO_DIRECT_DEVICE_OPEN, no device context") );
|
|
goto exit;
|
|
}
|
|
|
|
pContext = pIrpStack->FileObject->FsContext;
|
|
ASSERT(pContext);
|
|
|
|
DPF(DL_TRACE|FA_IOCTL, ("pWdmaContext=%08Xh", pContext) );
|
|
|
|
//
|
|
// force turds to be freed for a particular context
|
|
//
|
|
WdmaGrabMutex(pContext);
|
|
CleanupWaveDevices(pContext);
|
|
CleanupMidiDevices(pContext);
|
|
WdmaContextCleanup(pContext);
|
|
WdmaReleaseMutex(pContext);
|
|
|
|
exit:
|
|
pIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
pIrp->IoStatus.Information = 0;
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ValidateIoCode
|
|
(
|
|
IN ULONG IoCode
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
switch (IoCode)
|
|
{
|
|
case IOCTL_WDMAUD_INIT:
|
|
case IOCTL_WDMAUD_ADD_DEVNODE:
|
|
case IOCTL_WDMAUD_REMOVE_DEVNODE:
|
|
case IOCTL_WDMAUD_SET_PREFERRED_DEVICE:
|
|
case IOCTL_WDMAUD_GET_CAPABILITIES:
|
|
case IOCTL_WDMAUD_GET_NUM_DEVS:
|
|
case IOCTL_WDMAUD_OPEN_PIN:
|
|
case IOCTL_WDMAUD_CLOSE_PIN:
|
|
case IOCTL_WDMAUD_GET_VOLUME:
|
|
case IOCTL_WDMAUD_SET_VOLUME:
|
|
case IOCTL_WDMAUD_EXIT:
|
|
case IOCTL_WDMAUD_WAVE_OUT_PAUSE:
|
|
case IOCTL_WDMAUD_WAVE_OUT_PLAY:
|
|
case IOCTL_WDMAUD_WAVE_OUT_RESET:
|
|
case IOCTL_WDMAUD_WAVE_OUT_BREAKLOOP:
|
|
case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
|
|
case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
|
|
case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
|
|
case IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN:
|
|
case IOCTL_WDMAUD_WAVE_IN_STOP:
|
|
case IOCTL_WDMAUD_WAVE_IN_RECORD:
|
|
case IOCTL_WDMAUD_WAVE_IN_RESET:
|
|
case IOCTL_WDMAUD_WAVE_IN_GET_POS:
|
|
case IOCTL_WDMAUD_WAVE_IN_READ_PIN:
|
|
case IOCTL_WDMAUD_MIDI_OUT_RESET:
|
|
case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
|
|
case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
|
|
case IOCTL_WDMAUD_MIDI_OUT_WRITE_DATA:
|
|
case IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA:
|
|
case IOCTL_WDMAUD_MIDI_IN_STOP:
|
|
case IOCTL_WDMAUD_MIDI_IN_RECORD:
|
|
case IOCTL_WDMAUD_MIDI_IN_RESET:
|
|
case IOCTL_WDMAUD_MIDI_IN_READ_PIN:
|
|
case IOCTL_WDMAUD_MIXER_OPEN:
|
|
case IOCTL_WDMAUD_MIXER_CLOSE:
|
|
case IOCTL_WDMAUD_MIXER_GETLINEINFO:
|
|
case IOCTL_WDMAUD_MIXER_GETLINECONTROLS:
|
|
case IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS:
|
|
case IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS:
|
|
case IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA:
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
RETURN( Status );
|
|
}
|
|
|
|
NTSTATUS
|
|
ValidateDeviceType
|
|
(
|
|
IN ULONG IoCode,
|
|
IN DWORD DeviceType
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
switch (IoCode)
|
|
{
|
|
// These IOCTLs can handle any DeviceType
|
|
case IOCTL_WDMAUD_ADD_DEVNODE:
|
|
case IOCTL_WDMAUD_REMOVE_DEVNODE:
|
|
case IOCTL_WDMAUD_SET_PREFERRED_DEVICE:
|
|
case IOCTL_WDMAUD_GET_CAPABILITIES:
|
|
case IOCTL_WDMAUD_GET_NUM_DEVS:
|
|
case IOCTL_WDMAUD_OPEN_PIN:
|
|
case IOCTL_WDMAUD_CLOSE_PIN:
|
|
if (DeviceType != WaveInDevice &&
|
|
DeviceType != WaveOutDevice &&
|
|
DeviceType != MidiInDevice &&
|
|
DeviceType != MidiOutDevice &&
|
|
DeviceType != MixerDevice &&
|
|
DeviceType != AuxDevice)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
break;
|
|
|
|
// These IOCTLs can handle only AUX devices
|
|
case IOCTL_WDMAUD_GET_VOLUME:
|
|
case IOCTL_WDMAUD_SET_VOLUME:
|
|
if (DeviceType != AuxDevice)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
break;
|
|
|
|
// These IOCTLs can handle only WaveOut devices
|
|
case IOCTL_WDMAUD_WAVE_OUT_PAUSE:
|
|
case IOCTL_WDMAUD_WAVE_OUT_PLAY:
|
|
case IOCTL_WDMAUD_WAVE_OUT_RESET:
|
|
case IOCTL_WDMAUD_WAVE_OUT_BREAKLOOP:
|
|
case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
|
|
case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
|
|
case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
|
|
case IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN:
|
|
if (DeviceType != WaveOutDevice)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
break;
|
|
|
|
// These IOCTLs can handle only WaveIn devices
|
|
case IOCTL_WDMAUD_WAVE_IN_STOP:
|
|
case IOCTL_WDMAUD_WAVE_IN_RECORD:
|
|
case IOCTL_WDMAUD_WAVE_IN_RESET:
|
|
case IOCTL_WDMAUD_WAVE_IN_GET_POS:
|
|
case IOCTL_WDMAUD_WAVE_IN_READ_PIN:
|
|
if (DeviceType != WaveInDevice)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
break;
|
|
|
|
// These IOCTLs can handle only MidiOut devices
|
|
case IOCTL_WDMAUD_MIDI_OUT_RESET:
|
|
case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
|
|
case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
|
|
case IOCTL_WDMAUD_MIDI_OUT_WRITE_DATA:
|
|
case IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA:
|
|
if (DeviceType != MidiOutDevice)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
break;
|
|
|
|
// These IOCTLs can handle only MidiIn devices
|
|
case IOCTL_WDMAUD_MIDI_IN_STOP:
|
|
case IOCTL_WDMAUD_MIDI_IN_RECORD:
|
|
case IOCTL_WDMAUD_MIDI_IN_RESET:
|
|
case IOCTL_WDMAUD_MIDI_IN_READ_PIN:
|
|
if (DeviceType != MidiInDevice)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
break;
|
|
|
|
// These IOCTLs can handle only Mixer devices
|
|
case IOCTL_WDMAUD_MIXER_OPEN:
|
|
case IOCTL_WDMAUD_MIXER_CLOSE:
|
|
case IOCTL_WDMAUD_MIXER_GETLINEINFO:
|
|
case IOCTL_WDMAUD_MIXER_GETLINECONTROLS:
|
|
case IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS:
|
|
case IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS:
|
|
case IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA:
|
|
if (DeviceType != MixerDevice)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
break;
|
|
|
|
// No device type for these IOCTLs
|
|
case IOCTL_WDMAUD_INIT:
|
|
case IOCTL_WDMAUD_EXIT:
|
|
// Status is already STATUS_SUCCESS
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
RETURN( Status );
|
|
}
|
|
|
|
|
|
#ifdef _WIN64
|
|
|
|
// Note that on 64 bit Windows, handles have 32 bits of information in them,
|
|
// but no more. Thus they can be safely zero extended and truncated for thunks.
|
|
// All memory allocations made in 32 bit processes are guaranteed to be in the
|
|
// first 4 Gigs, again so that pointers from those processes can be thunked simply
|
|
// by zero extending them and truncating them.
|
|
|
|
VOID ThunkDeviceInfo3264(
|
|
LPDEVICEINFO32 DeviceInfo32,
|
|
LPDEVICEINFO DeviceInfo
|
|
)
|
|
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
DeviceInfo->Next = (LPDEVICEINFO)(UINT_PTR)DeviceInfo32->Next;
|
|
DeviceInfo->DeviceNumber = DeviceInfo32->DeviceNumber ;
|
|
DeviceInfo->DeviceType = DeviceInfo32->DeviceType ;
|
|
DeviceInfo->DeviceHandle = (HANDLE32)(UINT_PTR)DeviceInfo32->DeviceHandle ;
|
|
DeviceInfo->dwInstance = (DWORD_PTR)DeviceInfo32->dwInstance ;
|
|
DeviceInfo->dwCallback = (DWORD_PTR)DeviceInfo32->dwCallback ;
|
|
DeviceInfo->dwCallback16 = DeviceInfo32->dwCallback16 ;
|
|
DeviceInfo->dwFlags = DeviceInfo32->dwFlags ;
|
|
DeviceInfo->DataBuffer = (LPVOID)(UINT_PTR)DeviceInfo32->DataBuffer ;
|
|
DeviceInfo->DataBufferSize = DeviceInfo32->DataBufferSize ;
|
|
DeviceInfo->OpenDone = DeviceInfo32->OpenDone ;
|
|
DeviceInfo->OpenStatus = DeviceInfo32->OpenStatus ;
|
|
DeviceInfo->HardwareCallbackEventHandle = (HANDLE)(UINT_PTR)DeviceInfo32->HardwareCallbackEventHandle ;
|
|
DeviceInfo->dwCallbackType = DeviceInfo32->dwCallbackType ;
|
|
|
|
for (i=0; i<MAXCALLBACKS; i++)
|
|
DeviceInfo->dwID[i] = DeviceInfo32->dwID[i] ;
|
|
|
|
DeviceInfo->dwLineID = DeviceInfo32->dwLineID ;
|
|
DeviceInfo->ControlCallbackCount = DeviceInfo32->ControlCallbackCount ;
|
|
DeviceInfo->dwFormat = DeviceInfo32->dwFormat ;
|
|
DeviceInfo->mmr = DeviceInfo32->mmr ;
|
|
DeviceInfo->DeviceState = (LPDEVICESTATE)(UINT_PTR)DeviceInfo32->DeviceState ;
|
|
DeviceInfo->dwSig = DeviceInfo32->dwSig ;
|
|
wcsncpy(DeviceInfo->wstrDeviceInterface, DeviceInfo32->wstrDeviceInterface, MAXDEVINTERFACE+1) ;
|
|
|
|
}
|
|
|
|
VOID ThunkDeviceInfo6432(
|
|
LPDEVICEINFO DeviceInfo,
|
|
LPDEVICEINFO32 DeviceInfo32
|
|
)
|
|
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
DeviceInfo32->Next = (UINT32)(UINT_PTR)DeviceInfo->Next;
|
|
DeviceInfo32->DeviceNumber = DeviceInfo->DeviceNumber ;
|
|
DeviceInfo32->DeviceType = DeviceInfo->DeviceType ;
|
|
DeviceInfo32->DeviceHandle = (UINT32)(UINT_PTR)DeviceInfo->DeviceHandle ;
|
|
DeviceInfo32->dwInstance = (UINT32)DeviceInfo->dwInstance ;
|
|
DeviceInfo32->dwCallback = (UINT32)DeviceInfo->dwCallback ;
|
|
DeviceInfo32->dwCallback16 = DeviceInfo->dwCallback16 ;
|
|
DeviceInfo32->dwFlags = DeviceInfo->dwFlags ;
|
|
DeviceInfo32->DataBuffer = (UINT32)(UINT_PTR)DeviceInfo->DataBuffer ;
|
|
DeviceInfo32->DataBufferSize = DeviceInfo->DataBufferSize ;
|
|
DeviceInfo32->OpenDone = DeviceInfo->OpenDone ;
|
|
DeviceInfo32->OpenStatus = DeviceInfo->OpenStatus ;
|
|
DeviceInfo32->HardwareCallbackEventHandle = (UINT32)(UINT_PTR)DeviceInfo->HardwareCallbackEventHandle ;
|
|
DeviceInfo32->dwCallbackType = DeviceInfo->dwCallbackType ;
|
|
|
|
for (i=0; i<MAXCALLBACKS; i++)
|
|
DeviceInfo32->dwID[i] = DeviceInfo->dwID[i] ;
|
|
|
|
DeviceInfo32->dwLineID = DeviceInfo->dwLineID ;
|
|
DeviceInfo32->ControlCallbackCount = DeviceInfo->ControlCallbackCount ;
|
|
DeviceInfo32->dwFormat = DeviceInfo->dwFormat ;
|
|
DeviceInfo32->mmr = DeviceInfo->mmr ;
|
|
DeviceInfo32->DeviceState = (UINT32)(UINT_PTR)DeviceInfo->DeviceState ;
|
|
DeviceInfo32->dwSig = DeviceInfo->dwSig ;
|
|
wcscpy(DeviceInfo32->wstrDeviceInterface, DeviceInfo->wstrDeviceInterface) ;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
ValidateIrp
|
|
(
|
|
IN PIRP pIrp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
ULONG InputBufferLength;
|
|
ULONG OutputBufferLength;
|
|
LPDEVICEINFO DeviceInfo;
|
|
#ifdef _WIN64
|
|
LPDEVICEINFO32 DeviceInfo32;
|
|
LOCALDEVICEINFO LocalDeviceInfo;
|
|
#endif
|
|
LPVOID DataBuffer;
|
|
DWORD DataBufferSize;
|
|
ULONG IoCode;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
//
|
|
// Get the CurrentStackLocation and log it so we know what is going on
|
|
//
|
|
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
|
IoCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
//
|
|
// Checks to see that we have a WDMAUD Ioctl (buffered) request
|
|
//
|
|
Status = ValidateIoCode(IoCode);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Check the sizes of the input and output buffers.
|
|
//
|
|
InputBufferLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
|
|
OutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
|
|
if ((InputBufferLength < sizeof(DEVICEINFO32)) ||
|
|
(OutputBufferLength != sizeof(DEVICEINFO32)) )
|
|
{
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
if (IoCode == IOCTL_WDMAUD_WAVE_OUT_GET_POS)
|
|
{
|
|
DPF(DL_ERROR|FA_IOCTL, ("IOCTL_WDMAUD_WAVE_OUT_GET_POS: InputBufferLength = %d, OuputBufferLength = %d", InputBufferLength, OutputBufferLength));
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
// WARNING!!! If you add additional statements after the if that need
|
|
// to be part of this else clause, you will need to add brackets!
|
|
#endif
|
|
|
|
if ((InputBufferLength < sizeof(DEVICEINFO)) ||
|
|
(OutputBufferLength != sizeof(DEVICEINFO)) )
|
|
{
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
if (IoCode == IOCTL_WDMAUD_WAVE_OUT_GET_POS)
|
|
{
|
|
DPF(DL_WARNING|FA_IOCTL, ("IOCTL_WDMAUD_WAVE_OUT_GET_POS: InputBufferLength = %d, OuputBufferLength = %d", InputBufferLength, OutputBufferLength));
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
DeviceInfo32=((LPDEVICEINFO32)pIrp->AssociatedIrp.SystemBuffer);
|
|
RtlZeroMemory(&LocalDeviceInfo, sizeof(LOCALDEVICEINFO));
|
|
DeviceInfo=&LocalDeviceInfo.DeviceInfo;
|
|
ThunkDeviceInfo3264(DeviceInfo32, DeviceInfo);
|
|
}
|
|
else
|
|
// WARNING!!! If you add additional statements after the assignment that need
|
|
// to be part of this else clause, you will need to add brackets!
|
|
#endif
|
|
|
|
DeviceInfo = ((LPDEVICEINFO)pIrp->AssociatedIrp.SystemBuffer);
|
|
DataBuffer = DeviceInfo->DataBuffer;
|
|
DataBufferSize = DeviceInfo->DataBufferSize;
|
|
|
|
//
|
|
// Check to make sure that our DeviceInfo->wstrDeviceInterface is terminated
|
|
//
|
|
if (InputBufferLength % sizeof(WCHAR)) // must be WCHAR aligned
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Get the last widechar and compare with UNICODE_NULL
|
|
//
|
|
UINT TermCharPos;
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
TermCharPos = (InputBufferLength - sizeof(DEVICEINFO32)) / sizeof(WCHAR);
|
|
// Now make sure we had enough local buffer space to hold the whole string.
|
|
if (TermCharPos>MAXDEVINTERFACE) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
// Make sure we don't go past end of local buffer space when
|
|
// we check if the last character is null.
|
|
TermCharPos=MAXDEVINTERFACE;
|
|
}
|
|
}
|
|
else
|
|
// WARNING!!! If you add additional statements after the assignment that need
|
|
// to be part of this else clause, you will need to add brackets!
|
|
#endif
|
|
|
|
TermCharPos = (InputBufferLength - sizeof(DEVICEINFO)) / sizeof(WCHAR);
|
|
if (DeviceInfo->wstrDeviceInterface[TermCharPos] != UNICODE_NULL)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = ValidateDeviceType(IoCode,DeviceInfo->DeviceType);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Validate the pointers if the client is not trusted.
|
|
//
|
|
if (pIrp->RequestorMode != KernelMode)
|
|
{
|
|
if (DataBufferSize)
|
|
{
|
|
try
|
|
{
|
|
ASSERT(pIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL);
|
|
switch (IoCode)
|
|
{
|
|
//
|
|
// IoCode's that require a probe for reading
|
|
//
|
|
case IOCTL_WDMAUD_OPEN_PIN:
|
|
case IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN:
|
|
case IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA:
|
|
case IOCTL_WDMAUD_MIXER_OPEN:
|
|
case IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS:
|
|
ProbeForRead(DataBuffer,
|
|
DataBufferSize,
|
|
sizeof(BYTE));
|
|
break;
|
|
|
|
//
|
|
// IoCode's that require a probe for writing
|
|
//
|
|
case IOCTL_WDMAUD_GET_CAPABILITIES:
|
|
case IOCTL_WDMAUD_WAVE_IN_READ_PIN:
|
|
case IOCTL_WDMAUD_MIXER_GETLINEINFO:
|
|
case IOCTL_WDMAUD_MIXER_GETLINECONTROLS:
|
|
case IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS:
|
|
|
|
ProbeForWrite(DataBuffer,
|
|
DataBufferSize,
|
|
sizeof(BYTE));
|
|
break;
|
|
|
|
|
|
//
|
|
// IoCode's that require a probe for reading on DWORD alignment
|
|
//
|
|
case IOCTL_WDMAUD_SET_VOLUME:
|
|
case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
|
|
case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
|
|
ProbeForRead(DataBuffer,
|
|
DataBufferSize,
|
|
sizeof(DWORD));
|
|
break;
|
|
|
|
//
|
|
// IoCode's that require a probe for writing on DWORD alignment
|
|
//
|
|
case IOCTL_WDMAUD_GET_VOLUME:
|
|
case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
|
|
case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
|
|
case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
|
|
case IOCTL_WDMAUD_WAVE_IN_GET_POS:
|
|
case IOCTL_WDMAUD_MIDI_IN_READ_PIN:
|
|
ProbeForWrite(DataBuffer,
|
|
DataBufferSize,
|
|
sizeof(DWORD));
|
|
break;
|
|
|
|
// Don't know about this ioctl
|
|
default:
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Status = GetExceptionCode();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RETURN( Status );
|
|
}
|
|
|
|
|
|
//
|
|
// Helper routines.
|
|
//
|
|
|
|
NTSTATUS
|
|
ValidateAndTranslate(
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo,
|
|
DWORD ValidationSize,
|
|
ULONG *pTranslatedDeviceNumber
|
|
)
|
|
{
|
|
if (DeviceInfo->DataBufferSize != ValidationSize)
|
|
{
|
|
return STATUS_INVALID_BUFFER_SIZE;
|
|
}
|
|
|
|
*pTranslatedDeviceNumber = wdmaudTranslateDeviceNumber(pContext,
|
|
DeviceInfo->DeviceType,
|
|
DeviceInfo->wstrDeviceInterface,
|
|
DeviceInfo->DeviceNumber);
|
|
|
|
if (MAXULONG == *pTranslatedDeviceNumber) {
|
|
|
|
DPF(DL_WARNING|FA_IOCTL,("IOCTL_WDMAUD_SET_VOLUME: invalid device number, C %08x [%ls] DT %02x DN %02x",
|
|
pContext,
|
|
DeviceInfo->wstrDeviceInterface,
|
|
DeviceInfo->DeviceType,
|
|
DeviceInfo->DeviceNumber) );
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ValidateAndTranslateEx(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo,
|
|
#ifdef _WIN64
|
|
DWORD ValidationSize32,
|
|
#endif
|
|
DWORD ValidationSize,
|
|
ULONG *pTranslatedDeviceNumber
|
|
)
|
|
{
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
|
|
if (DeviceInfo->DataBufferSize != ValidationSize32)
|
|
{
|
|
RETURN( STATUS_INVALID_BUFFER_SIZE );
|
|
}
|
|
|
|
} else {
|
|
#endif
|
|
if (DeviceInfo->DataBufferSize != ValidationSize)
|
|
{
|
|
RETURN( STATUS_INVALID_BUFFER_SIZE );
|
|
}
|
|
#ifdef _WIN64
|
|
}
|
|
#endif
|
|
|
|
*pTranslatedDeviceNumber = wdmaudTranslateDeviceNumber(pContext,
|
|
DeviceInfo->DeviceType,
|
|
DeviceInfo->wstrDeviceInterface,
|
|
DeviceInfo->DeviceNumber);
|
|
if (MAXULONG == *pTranslatedDeviceNumber) {
|
|
|
|
DPF(DL_WARNING|FA_IOCTL,("IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA: invalid device number, C %08x [%ls] DT %02x DN %02x",
|
|
pContext,
|
|
DeviceInfo->wstrDeviceInterface,
|
|
DeviceInfo->DeviceType,
|
|
DeviceInfo->DeviceNumber) );
|
|
RETURN( STATUS_INVALID_PARAMETER );
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
//
|
|
// Now come the dispatch routines.
|
|
//
|
|
|
|
NTSTATUS
|
|
Dispatch_WaveOutWritePin(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo,
|
|
OUT BOOL *pCompletedIrp // TRUE if Irp was completed.
|
|
)
|
|
{
|
|
ULONG TranslatedDeviceNumber;
|
|
PSTREAM_HEADER_EX pStreamHeader;
|
|
LPWAVEHDR pWaveHdr = NULL;
|
|
#ifdef _WIN64
|
|
LPWAVEHDR32 pWaveHdr32;
|
|
#endif
|
|
PWRITE_CONTEXT pWriteContext = NULL;
|
|
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
|
|
//
|
|
// Verify that we received a valid waveheader
|
|
//
|
|
Status = ValidateAndTranslateEx(pIrp, pContext, DeviceInfo,
|
|
#ifdef _WIN64
|
|
sizeof(WAVEHDR32),
|
|
#endif
|
|
sizeof(WAVEHDR), &TranslatedDeviceNumber);
|
|
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
Status = AudioAllocateMemory_Fixed(sizeof(WRITE_CONTEXT) + sizeof(STREAM_HEADER_EX),
|
|
TAG_Audx_CONTEXT,
|
|
ZERO_FILL_MEMORY,
|
|
&pWriteContext);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
Status = CaptureBufferToLocalPool(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pWaveHdr
|
|
#ifdef _WIN64
|
|
,0
|
|
#endif
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
AudioFreeMemory( sizeof(WRITE_CONTEXT) + sizeof(STREAM_HEADER_EX),
|
|
&pWriteContext );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
// Thunk pWaveHdr to 64 bits.
|
|
pWaveHdr32=(LPWAVEHDR32)pWaveHdr;
|
|
pWriteContext->whInstance.wh.lpData=(LPSTR)(UINT_PTR)pWaveHdr32->lpData;
|
|
pWriteContext->whInstance.wh.dwBufferLength=pWaveHdr32->dwBufferLength;
|
|
pWriteContext->whInstance.wh.dwBytesRecorded=pWaveHdr32->dwBytesRecorded;
|
|
pWriteContext->whInstance.wh.dwUser=(DWORD_PTR)pWaveHdr32->dwUser;
|
|
pWriteContext->whInstance.wh.dwFlags=pWaveHdr32->dwFlags;
|
|
pWriteContext->whInstance.wh.dwLoops=pWaveHdr32->dwLoops;
|
|
pWriteContext->whInstance.wh.lpNext=(LPWAVEHDR)(UINT_PTR)pWaveHdr32->lpNext;
|
|
pWriteContext->whInstance.wh.reserved=(DWORD_PTR)pWaveHdr32->reserved;
|
|
} else {
|
|
#endif
|
|
//
|
|
// Copy the wavehdr to our local structure
|
|
//
|
|
RtlCopyMemory( &pWriteContext->whInstance.wh,
|
|
pWaveHdr,
|
|
sizeof(WAVEHDR));
|
|
#ifdef _WIN64
|
|
}
|
|
#endif
|
|
|
|
try
|
|
{
|
|
ProbeForRead(pWriteContext->whInstance.wh.lpData,
|
|
pWriteContext->whInstance.wh.dwBufferLength,
|
|
sizeof(BYTE));
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
AudioFreeMemory_Unknown( &pWaveHdr );
|
|
AudioFreeMemory( sizeof(WRITE_CONTEXT) + sizeof(STREAM_HEADER_EX),
|
|
&pWriteContext );
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
wdmaudMapBuffer ( pIrp,
|
|
(PVOID)pWriteContext->whInstance.wh.lpData,
|
|
pWriteContext->whInstance.wh.dwBufferLength,
|
|
&pWriteContext->whInstance.wh.lpData,
|
|
&pWriteContext->pBufferMdl,
|
|
pContext,
|
|
FALSE);
|
|
|
|
//
|
|
// If we get a zero-length buffer, it is alright to not have
|
|
// a kernel mapped buffer. Otherwise, fail if no Mdl or buffer.
|
|
//
|
|
if ( (pWriteContext->whInstance.wh.dwBufferLength != 0) &&
|
|
((NULL == pWriteContext->pBufferMdl) ||
|
|
(NULL == pWriteContext->whInstance.wh.lpData)) )
|
|
{
|
|
wdmaudUnmapBuffer( pWriteContext->pBufferMdl );
|
|
AudioFreeMemory_Unknown( &pWaveHdr );
|
|
AudioFreeMemory_Unknown( &pWriteContext );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
pWriteContext->whInstance.wh.reserved = (DWORD_PTR)pIrp; // store to complete later
|
|
pWriteContext->pCapturedWaveHdr = pWaveHdr;
|
|
|
|
pStreamHeader = (PSTREAM_HEADER_EX)(pWriteContext + 1);
|
|
pStreamHeader->Header.Data = pWriteContext->whInstance.wh.lpData;
|
|
|
|
//
|
|
// Must cleanup any mapped buffers and allocated memory
|
|
// on error paths in WriteWaveOutPin
|
|
//
|
|
Status = WriteWaveOutPin(&pContext->WaveOutDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle,
|
|
(LPWAVEHDR)pWriteContext,
|
|
pStreamHeader,
|
|
pIrp,
|
|
pContext,
|
|
pCompletedIrp );
|
|
//
|
|
// Upon return from this routine, pCompetedIrp will be set.
|
|
// if TRUE, the issue of the Irp was successful and it was
|
|
// marked pending when it was added to the delay queue. Thus
|
|
// we must not complete it a second time.
|
|
// If FALSE, there was some error and the Irp should be
|
|
// completed.
|
|
//
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Dispatch_WaveInReadPin(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo,
|
|
OUT BOOL *pCompletedIrp // TRUE if Irp was completed.
|
|
)
|
|
{
|
|
ULONG TranslatedDeviceNumber;
|
|
PSTREAM_HEADER_EX pStreamHeader = NULL;
|
|
LPWAVEHDR pWaveHdr;
|
|
#ifdef _WIN64
|
|
LPWAVEHDR32 pWaveHdr32;
|
|
#endif
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
|
|
//
|
|
// Assume that things will be successful. Write back that it's not completed.
|
|
//
|
|
*pCompletedIrp = FALSE;
|
|
|
|
//
|
|
// Verify that we received a valid waveheader
|
|
//
|
|
Status = ValidateAndTranslateEx(pIrp, pContext, DeviceInfo,
|
|
#ifdef _WIN64
|
|
sizeof(WAVEHDR32),
|
|
#endif
|
|
sizeof(WAVEHDR), &TranslatedDeviceNumber);
|
|
|
|
|
|
Status = AudioAllocateMemory_Fixed(sizeof(STREAM_HEADER_EX),
|
|
TAG_Audh_STREAMHEADER,
|
|
ZERO_FILL_MEMORY,
|
|
&pStreamHeader);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
wdmaudMapBuffer(pIrp,
|
|
DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pWaveHdr,
|
|
&pStreamHeader->pHeaderMdl,
|
|
pContext,
|
|
TRUE);
|
|
if (NULL == pStreamHeader->pHeaderMdl)
|
|
{
|
|
AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
LPVOID lpData;
|
|
DWORD dwBufferLength;
|
|
|
|
Status = CaptureBufferToLocalPool(
|
|
DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pStreamHeader->pWaveHdrAligned
|
|
#ifdef _WIN64
|
|
,(IoIs32bitProcess(pIrp))?sizeof(WAVEHDR):0
|
|
#endif
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
wdmaudUnmapBuffer( pStreamHeader->pHeaderMdl );
|
|
AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
// Thunk the wave header if required.
|
|
// Note this is an IN PLACE thunk, so we MUST do it in
|
|
// last element to first element order!!!
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
// Thunk pWaveHdrAligned to 64 bits.
|
|
pWaveHdr32=(LPWAVEHDR32)pStreamHeader->pWaveHdrAligned;
|
|
pStreamHeader->pWaveHdrAligned->reserved=(DWORD_PTR)pWaveHdr32->reserved;
|
|
pStreamHeader->pWaveHdrAligned->lpNext=(LPWAVEHDR)(UINT_PTR)pWaveHdr32->lpNext;
|
|
pStreamHeader->pWaveHdrAligned->dwLoops=pWaveHdr32->dwLoops;
|
|
pStreamHeader->pWaveHdrAligned->dwFlags=pWaveHdr32->dwFlags;
|
|
pStreamHeader->pWaveHdrAligned->dwUser=(DWORD_PTR)pWaveHdr32->dwUser;
|
|
pStreamHeader->pWaveHdrAligned->dwBytesRecorded=pWaveHdr32->dwBytesRecorded;
|
|
pStreamHeader->pWaveHdrAligned->dwBufferLength=pWaveHdr32->dwBufferLength;
|
|
pStreamHeader->pWaveHdrAligned->lpData=(LPSTR)(UINT_PTR)pWaveHdr32->lpData;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Capture these parameters before probing
|
|
//
|
|
lpData = pStreamHeader->pWaveHdrAligned->lpData;
|
|
dwBufferLength = pStreamHeader->pWaveHdrAligned->dwBufferLength;
|
|
|
|
try
|
|
{
|
|
ProbeForWrite(lpData,
|
|
dwBufferLength,
|
|
sizeof(BYTE));
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
AudioFreeMemory_Unknown( &pStreamHeader->pWaveHdrAligned );
|
|
wdmaudUnmapBuffer(pStreamHeader->pHeaderMdl);
|
|
AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
wdmaudMapBuffer( pIrp,
|
|
lpData,
|
|
dwBufferLength,
|
|
&pStreamHeader->Header.Data,
|
|
&pStreamHeader->pBufferMdl,
|
|
pContext,
|
|
TRUE); // will be freed on completion
|
|
|
|
//
|
|
// If we get a zero-length buffer, it is alright to not have
|
|
// a kernel mapped buffer. Otherwise, fail if no Mdl or buffer.
|
|
//
|
|
if ( (dwBufferLength != 0) &&
|
|
((NULL == pStreamHeader->pBufferMdl) ||
|
|
(NULL == pStreamHeader->Header.Data)) )
|
|
{
|
|
wdmaudUnmapBuffer(pStreamHeader->pBufferMdl);
|
|
AudioFreeMemory_Unknown( &pStreamHeader->pWaveHdrAligned );
|
|
wdmaudUnmapBuffer(pStreamHeader->pHeaderMdl);
|
|
AudioFreeMemory_Unknown( &pStreamHeader );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
pStreamHeader->pIrp = pIrp; // store so we can complete later
|
|
pStreamHeader->Header.FrameExtent = dwBufferLength ;
|
|
pStreamHeader->pdwBytesRecorded = &pWaveHdr->dwBytesRecorded; // store so we can use later
|
|
#ifdef _WIN64
|
|
// Fixup dwBytesRecorded pointer for 32 bit irps.
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
pStreamHeader->pdwBytesRecorded = &((LPWAVEHDR32)pWaveHdr)->dwBytesRecorded;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Must cleanup any mapped buffers and allocated memory
|
|
// on error paths in ReadWaveInPin
|
|
//
|
|
Status = ReadWaveInPin( &pContext->WaveInDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle,
|
|
pStreamHeader,
|
|
pIrp,
|
|
pContext,
|
|
pCompletedIrp );
|
|
//
|
|
// If ReadWaveInPin returns something other then STATUS_PENDING
|
|
// we could have problems.
|
|
//
|
|
ASSERT(Status == STATUS_PENDING);
|
|
}
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
Dispatch_MidiInReadPin(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo,
|
|
OUT BOOL *pCompletedIrp // TRUE if Irp was completed.
|
|
)
|
|
{
|
|
ULONG TranslatedDeviceNumber;
|
|
PMIDIINHDR pNewMidiInHdr = NULL;
|
|
LPMIDIDATA pMidiData;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
|
|
//
|
|
// Assume that things will be successful. Write back that it's not completed.
|
|
//
|
|
ASSERT(FALSE == *pCompletedIrp );
|
|
|
|
//
|
|
// Verify that we received a valid mididata structure
|
|
//
|
|
Status = ValidateAndTranslate(pContext,
|
|
DeviceInfo,
|
|
sizeof(MIDIDATA),
|
|
&TranslatedDeviceNumber);
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
Status = AudioAllocateMemory_Fixed(sizeof(*pNewMidiInHdr),
|
|
TAG_Aude_MIDIHEADER,
|
|
ZERO_FILL_MEMORY,
|
|
&pNewMidiInHdr);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
wdmaudMapBuffer( pIrp,
|
|
DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMidiData,
|
|
&pNewMidiInHdr->pMdl,
|
|
pContext,
|
|
TRUE);
|
|
if (NULL == pNewMidiInHdr->pMdl)
|
|
{
|
|
AudioFreeMemory( sizeof(*pNewMidiInHdr),&pNewMidiInHdr );
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
PWDMAPENDINGIRP_CONTEXT pPendingIrpContext;
|
|
|
|
//
|
|
// wdmaudPreparteIrp marks the irp as pending, thus
|
|
// we must not complete the irp when we get to this
|
|
// point in the code.
|
|
//
|
|
Status = wdmaudPrepareIrp ( pIrp, MidiInDevice, pContext, &pPendingIrpContext );
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Initialize this new MidiIn header
|
|
//
|
|
pNewMidiInHdr->pMidiData = pMidiData;
|
|
pNewMidiInHdr->pIrp = pIrp;
|
|
pNewMidiInHdr->pPendingIrpContext = pPendingIrpContext;
|
|
|
|
//
|
|
// Add this header to the tail of the queue
|
|
//
|
|
// Must cleanup any mapped buffers and allocated memory
|
|
// on error paths in AddBufferToMidiInQueue
|
|
//
|
|
Status = AddBufferToMidiInQueue( pContext->MidiInDevs[TranslatedDeviceNumber].pMidiPin,
|
|
pNewMidiInHdr );
|
|
|
|
if (STATUS_PENDING != Status)
|
|
{
|
|
// Must have been an error, complete Irp
|
|
wdmaudUnmapBuffer( pNewMidiInHdr->pMdl );
|
|
AudioFreeMemory_Unknown( &pNewMidiInHdr );
|
|
|
|
wdmaudUnprepareIrp( pIrp, Status, 0, pPendingIrpContext );
|
|
|
|
}
|
|
//
|
|
// because we marked the irp pending, we don't want to
|
|
// complete it when we return. So, tell the caller not
|
|
// to complete the Irp.
|
|
//
|
|
*pCompletedIrp = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Dispatch_State(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo,
|
|
ULONG IoCode
|
|
)
|
|
{
|
|
ULONG TranslatedDeviceNumber;
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
|
|
Status = ValidateAndTranslate(pContext,
|
|
DeviceInfo,
|
|
0,
|
|
&TranslatedDeviceNumber);
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
switch(IoCode)
|
|
{
|
|
//
|
|
// Midi out state changes
|
|
//
|
|
case IOCTL_WDMAUD_MIDI_OUT_RESET:
|
|
Status = StateMidiOutPin ( pContext->MidiOutDevs[TranslatedDeviceNumber].pMidiPin,
|
|
KSSTATE_STOP );
|
|
break;
|
|
case IOCTL_WDMAUD_MIDI_OUT_WRITE_DATA:
|
|
Status = WriteMidiEventPin(&pContext->MidiOutDevs[TranslatedDeviceNumber],
|
|
PtrToUlong(DeviceInfo->DataBuffer));
|
|
break;
|
|
|
|
//
|
|
// Midi in state changes
|
|
//
|
|
case IOCTL_WDMAUD_MIDI_IN_STOP:
|
|
Status = StateMidiInPin ( pContext->MidiInDevs[TranslatedDeviceNumber].pMidiPin,
|
|
KSSTATE_PAUSE );
|
|
break;
|
|
case IOCTL_WDMAUD_MIDI_IN_RECORD:
|
|
Status = StateMidiInPin ( pContext->MidiInDevs[TranslatedDeviceNumber].pMidiPin,
|
|
KSSTATE_RUN );
|
|
break;
|
|
case IOCTL_WDMAUD_MIDI_IN_RESET:
|
|
Status = ResetMidiInPin ( pContext->MidiInDevs[TranslatedDeviceNumber].pMidiPin );
|
|
break;
|
|
|
|
|
|
//
|
|
// Wave out state changes
|
|
//
|
|
|
|
case IOCTL_WDMAUD_WAVE_OUT_PAUSE:
|
|
Status = StateWavePin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle,
|
|
KSSTATE_PAUSE );
|
|
break;
|
|
case IOCTL_WDMAUD_WAVE_OUT_PLAY:
|
|
Status = StateWavePin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle,
|
|
KSSTATE_RUN );
|
|
break;
|
|
case IOCTL_WDMAUD_WAVE_OUT_RESET:
|
|
Status = StateWavePin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle,
|
|
KSSTATE_PAUSE );
|
|
if ( NT_SUCCESS(Status) )
|
|
{
|
|
Status = ResetWaveOutPin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle ) ;
|
|
}
|
|
break;
|
|
case IOCTL_WDMAUD_WAVE_OUT_BREAKLOOP:
|
|
Status = BreakLoopWaveOutPin ( &pContext->WaveOutDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle );
|
|
break;
|
|
|
|
//
|
|
// Wave In State changes
|
|
//
|
|
|
|
case IOCTL_WDMAUD_WAVE_IN_STOP:
|
|
Status = StateWavePin ( &pContext->WaveInDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle,
|
|
KSSTATE_PAUSE );
|
|
break;
|
|
case IOCTL_WDMAUD_WAVE_IN_RECORD:
|
|
Status = StateWavePin ( &pContext->WaveInDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle,
|
|
KSSTATE_RUN );
|
|
break;
|
|
case IOCTL_WDMAUD_WAVE_IN_RESET:
|
|
Status = StateWavePin ( &pContext->WaveInDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle,
|
|
KSSTATE_STOP );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Dispatch_GetCapabilities(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo
|
|
)
|
|
{
|
|
ULONG TranslatedDeviceNumber;
|
|
PVOID pMappedBuffer;
|
|
PMDL pMdl;
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
|
|
//
|
|
// Passing in DeviceInfo->DataBufferSize as the validation size because we don't care
|
|
// about the buffer check but we still want the translation code. It's just a short
|
|
// cut on the ValidateAndTranslate function.
|
|
//
|
|
Status = ValidateAndTranslate(pContext,
|
|
DeviceInfo,
|
|
DeviceInfo->DataBufferSize, // Don't care about buffer
|
|
&TranslatedDeviceNumber);
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
//
|
|
// Map this buffer into a system address
|
|
//
|
|
wdmaudMapBuffer( pIrp,
|
|
DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer,
|
|
&pMdl,
|
|
pContext,
|
|
TRUE);
|
|
if (NULL == pMappedBuffer)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
Status = wdmaudGetDevCaps( pContext,
|
|
DeviceInfo->DeviceType,
|
|
TranslatedDeviceNumber,
|
|
pMappedBuffer,
|
|
DeviceInfo->DataBufferSize);
|
|
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
|
|
//
|
|
// Free the MDL
|
|
//
|
|
wdmaudUnmapBuffer( pMdl );
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Dispatch_OpenPin(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo
|
|
)
|
|
{
|
|
ULONG TranslatedDeviceNumber;
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
|
|
//
|
|
// Passing in DeviceInfo->DataBufferSize as the validation size because we don't care
|
|
// about the buffer check but we still want the translation code. It's just a short
|
|
// cut on the ValidateAndTranslate function.
|
|
//
|
|
Status = ValidateAndTranslate(pContext,
|
|
DeviceInfo,
|
|
DeviceInfo->DataBufferSize, // Don't care about buffer
|
|
&TranslatedDeviceNumber);
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
switch (DeviceInfo->DeviceType)
|
|
{
|
|
case WaveOutDevice:
|
|
case WaveInDevice:
|
|
|
|
if (DeviceInfo->DataBufferSize < sizeof(PCMWAVEFORMAT))
|
|
{
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
} else {
|
|
LPWAVEFORMATEX pWaveFmt = NULL;
|
|
|
|
//
|
|
// Ensure alignment by copying to temporary buffer
|
|
//
|
|
Status = CaptureBufferToLocalPool(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pWaveFmt
|
|
#ifdef _WIN64
|
|
,0
|
|
#endif
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
if ((pWaveFmt->wFormatTag != WAVE_FORMAT_PCM) &&
|
|
((DeviceInfo->DataBufferSize < sizeof(WAVEFORMATEX)) ||
|
|
(DeviceInfo->DataBufferSize != sizeof(WAVEFORMATEX) + pWaveFmt->cbSize)))
|
|
{
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
}
|
|
else
|
|
{
|
|
Status = OpenWavePin( pContext,
|
|
TranslatedDeviceNumber,
|
|
pWaveFmt,
|
|
DeviceInfo->DeviceHandle,
|
|
DeviceInfo->dwFlags,
|
|
(WaveOutDevice == DeviceInfo->DeviceType?
|
|
KSPIN_DATAFLOW_IN:KSPIN_DATAFLOW_OUT) );
|
|
}
|
|
|
|
//
|
|
// Free the temporary buffer
|
|
//
|
|
AudioFreeMemory_Unknown( &pWaveFmt );
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case MidiOutDevice:
|
|
Status = OpenMidiPin( pContext, TranslatedDeviceNumber, KSPIN_DATAFLOW_IN );
|
|
break;
|
|
|
|
case MidiInDevice:
|
|
Status = OpenMidiPin( pContext, TranslatedDeviceNumber, KSPIN_DATAFLOW_OUT );
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Dispatch_ClosePin(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo
|
|
)
|
|
{
|
|
ULONG TranslatedDeviceNumber;
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
|
|
Status = ValidateAndTranslate(pContext,
|
|
DeviceInfo,
|
|
0,
|
|
&TranslatedDeviceNumber);
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
switch (DeviceInfo->DeviceType)
|
|
{
|
|
case WaveOutDevice:
|
|
CloseTheWavePin( &pContext->WaveOutDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle );
|
|
break;
|
|
|
|
case WaveInDevice:
|
|
CloseTheWavePin( &pContext->WaveInDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle );
|
|
break;
|
|
|
|
case MidiOutDevice:
|
|
CloseMidiDevicePin( &pContext->MidiOutDevs[TranslatedDeviceNumber] );
|
|
break;
|
|
|
|
case MidiInDevice:
|
|
CloseMidiDevicePin( &pContext->MidiInDevs[TranslatedDeviceNumber] );
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Dispatch_GetVolume(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo,
|
|
ULONG IoCode
|
|
)
|
|
{
|
|
DWORD dwLeft, dwRight;
|
|
ULONG TranslatedDeviceNumber;
|
|
PVOID pMappedBuffer;
|
|
PMDL pMdl;
|
|
ULONG ulDeviceType;
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
|
|
Status = ValidateAndTranslate(pContext,
|
|
DeviceInfo,
|
|
sizeof(DWORD),
|
|
&TranslatedDeviceNumber);
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
switch(IoCode)
|
|
{
|
|
case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
|
|
ulDeviceType = MidiOutDevice;
|
|
break;
|
|
case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
|
|
ulDeviceType = WaveOutDevice;
|
|
break;
|
|
case IOCTL_WDMAUD_GET_VOLUME:
|
|
ulDeviceType = DeviceInfo->DeviceType;
|
|
break;
|
|
default:
|
|
return STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
Status = GetVolume(pContext,
|
|
TranslatedDeviceNumber,
|
|
ulDeviceType,
|
|
&dwLeft,
|
|
&dwRight);
|
|
if( NT_SUCCESS( Status ) )
|
|
{
|
|
wdmaudMapBuffer( pIrp, // Wave buffers look like
|
|
DeviceInfo->DataBuffer, // DeviceInfo->DataBuffer
|
|
DeviceInfo->DataBufferSize, // DeviceInfo->DataBufferSize
|
|
&pMappedBuffer,
|
|
&pMdl,
|
|
pContext,
|
|
TRUE);
|
|
if (NULL == pMappedBuffer)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
//
|
|
// Write this info back.
|
|
//
|
|
*((LPDWORD)pMappedBuffer) = MAKELONG(LOWORD(dwLeft),
|
|
LOWORD(dwRight));
|
|
wdmaudUnmapBuffer( pMdl );
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
}
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Dispatch_SetVolume(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo,
|
|
ULONG IoCode
|
|
)
|
|
{
|
|
ULONG TranslatedDeviceNumber;
|
|
PVOID pMappedBuffer;
|
|
PMDL pMdl;
|
|
ULONG ulDeviceType;
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
|
|
Status = ValidateAndTranslate(pContext,
|
|
DeviceInfo,
|
|
sizeof(DWORD),
|
|
&TranslatedDeviceNumber);
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
wdmaudMapBuffer( pIrp,
|
|
DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer,
|
|
&pMdl,
|
|
pContext,
|
|
TRUE);
|
|
if (NULL == pMappedBuffer)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
switch(IoCode)
|
|
{
|
|
case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
|
|
ulDeviceType = MidiOutDevice;
|
|
break;
|
|
case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
|
|
ulDeviceType = WaveOutDevice;
|
|
break;
|
|
case IOCTL_WDMAUD_SET_VOLUME:
|
|
ulDeviceType = DeviceInfo->DeviceType;
|
|
break;
|
|
default:
|
|
return STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
Status = SetVolume(pContext,
|
|
TranslatedDeviceNumber,
|
|
ulDeviceType,
|
|
LOWORD(*((LPDWORD)pMappedBuffer)),
|
|
HIWORD(*((LPDWORD)pMappedBuffer)));
|
|
|
|
wdmaudUnmapBuffer( pMdl );
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Dispatch_WaveGetPos(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo,
|
|
ULONG IoCode
|
|
)
|
|
{
|
|
WAVEPOSITION WavePos;
|
|
ULONG TranslatedDeviceNumber;
|
|
PVOID pMappedBuffer;
|
|
PMDL pMdl;
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
|
|
Status = ValidateAndTranslate(pContext,
|
|
DeviceInfo,
|
|
sizeof(DWORD),
|
|
&TranslatedDeviceNumber);
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
//
|
|
// Map this buffer into a system address
|
|
//
|
|
wdmaudMapBuffer( pIrp,
|
|
DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer,
|
|
&pMdl,
|
|
pContext,
|
|
TRUE);
|
|
if (NULL == pMappedBuffer)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
WavePos.Operation = KSPROPERTY_TYPE_GET;
|
|
switch(IoCode)
|
|
{
|
|
case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
|
|
Status = PosWavePin(&pContext->WaveOutDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle,
|
|
&WavePos );
|
|
break;
|
|
case IOCTL_WDMAUD_WAVE_IN_GET_POS:
|
|
Status = PosWavePin ( &pContext->WaveInDevs[TranslatedDeviceNumber],
|
|
DeviceInfo->DeviceHandle,
|
|
&WavePos );
|
|
break;
|
|
default:
|
|
return STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
*((LPDWORD)pMappedBuffer) = WavePos.BytePos;
|
|
|
|
//
|
|
// Free the MDL
|
|
//
|
|
wdmaudUnmapBuffer( pMdl );
|
|
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Dispatch_MidiOutWriteLongdata(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo,
|
|
BOOL *pCompletedIrp
|
|
)
|
|
{
|
|
ULONG TranslatedDeviceNumber;
|
|
LPMIDIHDR pMidiHdr = NULL;
|
|
#ifdef _WIN64
|
|
LPMIDIHDR32 pMidiHdr32;
|
|
#endif
|
|
PSTREAM_HEADER_EX pStreamHeader = NULL;
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
|
|
ASSERT( FALSE == *pCompletedIrp );
|
|
//
|
|
// Verify that we received a valid midiheader
|
|
//
|
|
Status = ValidateAndTranslateEx(pIrp, pContext, DeviceInfo,
|
|
#ifdef _WIN64
|
|
sizeof(MIDIHDR32),
|
|
#endif
|
|
sizeof(MIDIHDR), &TranslatedDeviceNumber);
|
|
if( !NT_SUCCESS(Status) )
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
Status = AudioAllocateMemory_Fixed(sizeof(STREAM_HEADER_EX),
|
|
TAG_Audh_STREAMHEADER,
|
|
ZERO_FILL_MEMORY,
|
|
&pStreamHeader);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
Status = CaptureBufferToLocalPool(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMidiHdr
|
|
#ifdef _WIN64
|
|
,(IoIs32bitProcess(pIrp))?sizeof(MIDIHDR):0
|
|
#endif
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
|
|
//
|
|
// Why do we change the status here?
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
LPVOID lpData;
|
|
DWORD dwBufferLength;
|
|
|
|
#ifdef _WIN64
|
|
// Thunk the midi header if required.
|
|
// Note this is an IN PLACE thunk, so we MUST do it in
|
|
// last element to first element order!!!
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
// Thunk pMidiHdr to 64 bits.
|
|
pMidiHdr32=(LPMIDIHDR32)pMidiHdr;
|
|
#if (WINVER >= 0x0400)
|
|
{
|
|
ULONG i;
|
|
// Again we must go from LAST element to first element in this array.
|
|
// This IS the reverse of for (i=0; i<(sizeof(pMidiHdr32->dwReserved)/sizeof(UINT32)); i++)
|
|
for (i=(sizeof(pMidiHdr32->dwReserved)/sizeof(UINT32)); i--;) {
|
|
pMidiHdr->dwReserved[i]=(DWORD_PTR)pMidiHdr32->dwReserved[i];
|
|
}
|
|
}
|
|
pMidiHdr->dwOffset=pMidiHdr32->dwOffset;
|
|
#endif
|
|
pMidiHdr->reserved=(DWORD_PTR)pMidiHdr32->reserved;
|
|
pMidiHdr->lpNext=(LPMIDIHDR)(UINT_PTR)pMidiHdr32->lpNext;
|
|
pMidiHdr->dwFlags=pMidiHdr32->dwFlags;
|
|
pMidiHdr->dwUser=(DWORD_PTR)pMidiHdr32->dwUser;
|
|
pMidiHdr->dwBytesRecorded=pMidiHdr32->dwBytesRecorded;
|
|
pMidiHdr->dwBufferLength=pMidiHdr32->dwBufferLength;
|
|
pMidiHdr->lpData=(LPSTR)(UINT_PTR)pMidiHdr32->lpData;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Capture these parameters before probing
|
|
//
|
|
lpData = pMidiHdr->lpData;
|
|
dwBufferLength = pMidiHdr->dwBufferLength;
|
|
|
|
try
|
|
{
|
|
ProbeForRead(lpData, dwBufferLength, sizeof(BYTE));
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
AudioFreeMemory_Unknown( &pMidiHdr );
|
|
AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
wdmaudMapBuffer(pIrp,
|
|
lpData,
|
|
dwBufferLength,
|
|
&pStreamHeader->Header.Data,
|
|
&pStreamHeader->pBufferMdl,
|
|
pContext,
|
|
TRUE); // will be freed on completion
|
|
|
|
//
|
|
// If we get a zero-length buffer, it is alright to not have
|
|
// a kernel mapped buffer. Otherwise, fail if no Mdl or buffer.
|
|
//
|
|
if ( (dwBufferLength != 0) &&
|
|
((NULL == pStreamHeader->pBufferMdl) ||
|
|
(NULL == pStreamHeader->Header.Data)) )
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
wdmaudUnmapBuffer(pStreamHeader->pBufferMdl);
|
|
AudioFreeMemory_Unknown( &pMidiHdr );
|
|
AudioFreeMemory( sizeof(STREAM_HEADER_EX),&pStreamHeader );
|
|
|
|
} else {
|
|
|
|
pStreamHeader->pIrp = pIrp; // store so we can complete later
|
|
pStreamHeader->pMidiPin =
|
|
pContext->MidiOutDevs[TranslatedDeviceNumber].pMidiPin;
|
|
pStreamHeader->Header.FrameExtent = dwBufferLength;
|
|
|
|
//
|
|
// Must cleanup any mapped buffers and allocated memory
|
|
// on error paths in WriteMidiOutPin
|
|
//
|
|
Status = WriteMidiOutPin( pMidiHdr,pStreamHeader,pCompletedIrp );
|
|
|
|
//
|
|
// Because WriteMidiOutPin is synchronous, pCompetedIrp will
|
|
// always come back FALSE so that the caller can clean up the
|
|
// Irp.
|
|
//
|
|
ASSERT( FALSE == *pCompletedIrp );
|
|
}
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ValidateAndCapture(
|
|
PIRP pIrp,
|
|
LPDEVICEINFO DeviceInfo,
|
|
#ifdef _WIN64
|
|
DWORD ValidationSize32,
|
|
#endif
|
|
DWORD ValidationSize,
|
|
PVOID *ppMappedBuffer
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Assume that we're going to have a problem.
|
|
//
|
|
*ppMappedBuffer = NULL;
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
|
|
if (DeviceInfo->DataBufferSize != ValidationSize32)
|
|
{
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
return STATUS_INVALID_BUFFER_SIZE;
|
|
}
|
|
|
|
} else {
|
|
#endif
|
|
if (DeviceInfo->DataBufferSize != ValidationSize)
|
|
{
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
return STATUS_INVALID_BUFFER_SIZE;
|
|
}
|
|
#ifdef _WIN64
|
|
}
|
|
#endif
|
|
//
|
|
// Copy to local data storage
|
|
//
|
|
Status = CaptureBufferToLocalPool(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
ppMappedBuffer
|
|
#ifdef _WIN64
|
|
,(IoIs32bitProcess(pIrp))?ValidationSize:0
|
|
#endif
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Dispatch_GetLineInfo(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo
|
|
)
|
|
{
|
|
PVOID pMappedBuffer;
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
//
|
|
// The size specified in this member must be large enough to
|
|
// contain the base MIXERLINE structure.
|
|
//
|
|
Status = ValidateAndCapture(pIrp,DeviceInfo,
|
|
#ifdef _WIN64
|
|
sizeof(MIXERLINE32),
|
|
#endif
|
|
sizeof(MIXERLINE), &pMappedBuffer);
|
|
if( !NT_SUCCESS(Status) )
|
|
{
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
goto Exit;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
// Now thunk the MIXERLINE structure to 64 bits.
|
|
// WARNING we do this a simple easy way, but it is DEPENDENT on the
|
|
// structure of MIXERLINE. There is currently only 1 parameter that
|
|
// changes in size between the 32 and 64 bit structures. dwUser.
|
|
// This will have to get more complicated if the MIXERLINE structure
|
|
// ever has more stuff in it that needs to be thunked.
|
|
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
|
|
// First move everything following the dwUser field in the 32 bit
|
|
// structure down 4 bytes.
|
|
RtlMoveMemory(&((PMIXERLINE32)pMappedBuffer)->cChannels,
|
|
&((PMIXERLINE32)pMappedBuffer)->dwComponentType,
|
|
sizeof(MIXERLINE32)-FIELD_OFFSET(MIXERLINE32,dwComponentType));
|
|
|
|
// Now thunk dwUser to 64 bits.
|
|
((PMIXERLINE)pMappedBuffer)->dwUser=(DWORD_PTR)((PMIXERLINE32)pMappedBuffer)->dwUser;
|
|
|
|
}
|
|
#endif
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = kmxlGetLineInfoHandler( pContext, DeviceInfo, pMappedBuffer );
|
|
//
|
|
// This call should have set the DeviceInfo->mmr and returned a valid
|
|
// NTSTATUS value.
|
|
//
|
|
|
|
#ifdef _WIN64
|
|
// Now thunk the MIXERLINE structure back to 32 bits.
|
|
// WARNING we do this a simple easy way, but it is DEPENDENT on the
|
|
// structure of MIXERLINE. There is currently only 1 parameter that
|
|
// changes in size between the 32 and 64 bit structures. dwUser.
|
|
// This will have to get more complicated if the MIXERLINE structure
|
|
// ever has more stuff in it that needs to be thunked.
|
|
|
|
// Note that for in place thunks we must do them from LAST to FIRST
|
|
// field order when thunking up to 64 bits and in FIRST to LAST
|
|
// field order when thunking back down to 32 bits!!!
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
|
|
// Just move everything that now is after dwComponentType back up 4 bytes.
|
|
RtlMoveMemory(&((PMIXERLINE32)pMappedBuffer)->dwComponentType,
|
|
&((PMIXERLINE32)pMappedBuffer)->cChannels,
|
|
sizeof(MIXERLINE32)-FIELD_OFFSET(MIXERLINE32,dwComponentType));
|
|
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Copy back the contents of the captured buffer
|
|
//
|
|
CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer);
|
|
}
|
|
|
|
Exit:
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Dispatch_GetLineControls(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo
|
|
)
|
|
{
|
|
PVOID pamxctrl = NULL;
|
|
PVOID pamxctrlUnmapped;
|
|
DWORD dwSize;
|
|
PVOID pMappedBuffer;
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success
|
|
|
|
//
|
|
// The size specified in this member must be large enough to
|
|
// contain the base MIXERLINECONTROL structure.
|
|
//
|
|
Status = ValidateAndCapture(pIrp,DeviceInfo,
|
|
#ifdef _WIN64
|
|
sizeof(MIXERLINECONTROLS32),
|
|
#endif
|
|
sizeof(MIXERLINECONTROLS), &pMappedBuffer);
|
|
if( !NT_SUCCESS(Status) )
|
|
{
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
#ifdef _WIN64
|
|
// Now thunk the MIXERLINECONTROL structure to 64 bits.
|
|
// Currently this is easy to do as only the last field is different
|
|
// in size and simply needs to be zero extended.
|
|
|
|
// NOTE: This structure also thus does NOT need any thunking in
|
|
// the reverse direction! How nice.
|
|
|
|
// NOTE: None of the mixer controls themselves need any thunking.
|
|
// YEAH!!!
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
|
|
((LPMIXERLINECONTROLS)pMappedBuffer)->pamxctrl=(LPMIXERCONTROL)(UINT_PTR)((LPMIXERLINECONTROLS32)pMappedBuffer)->pamxctrl;
|
|
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Pick reasonable max values for the size and number of controls to eliminate overflow
|
|
//
|
|
if ( ( ((LPMIXERLINECONTROLS) pMappedBuffer)->cbmxctrl > 10000 ) ||
|
|
( ((LPMIXERLINECONTROLS) pMappedBuffer)->cControls > 10000 ) )
|
|
{
|
|
CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer);
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
pamxctrlUnmapped = ((LPMIXERLINECONTROLS) pMappedBuffer)->pamxctrl;
|
|
dwSize = ((LPMIXERLINECONTROLS) pMappedBuffer)->cbmxctrl *
|
|
((LPMIXERLINECONTROLS) pMappedBuffer)->cControls;
|
|
try
|
|
{
|
|
ProbeForWrite(pamxctrlUnmapped, dwSize, sizeof(DWORD));
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer);
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
Status = GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Map the array of mixer controls into system space. The
|
|
// size of this buffer is the number of controls times the
|
|
// size of each control.
|
|
//
|
|
Status = CaptureBufferToLocalPool(pamxctrlUnmapped,
|
|
dwSize,
|
|
&pamxctrl
|
|
#ifdef _WIN64
|
|
,0
|
|
#endif
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Call the handler.
|
|
//
|
|
Status = kmxlGetLineControlsHandler(pContext,
|
|
DeviceInfo,
|
|
pMappedBuffer,
|
|
pamxctrl );
|
|
//
|
|
// The previous call should have set the DeviceInfo->mmr and returned
|
|
// a valid Status value.
|
|
//
|
|
|
|
CopyAndFreeCapturedBuffer(pamxctrlUnmapped,
|
|
dwSize,
|
|
&pamxctrl);
|
|
} else {
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
}
|
|
} else {
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
}
|
|
|
|
CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer);
|
|
Exit:
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
return Status;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
|
|
void
|
|
ThunkMixerControlDetails_Enter(
|
|
PVOID pMappedBuffer
|
|
)
|
|
{
|
|
// Now thunk the MIXERCONTROLDETAILS structure to 64 bits.
|
|
// This is an IN PLACE thunk, so MUST be done from last to first fields.
|
|
|
|
((LPMIXERCONTROLDETAILS)pMappedBuffer)->paDetails=(LPVOID)(UINT_PTR)((LPMIXERCONTROLDETAILS32)pMappedBuffer)->paDetails;
|
|
((LPMIXERCONTROLDETAILS)pMappedBuffer)->cbDetails=((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cbDetails;
|
|
// We always thunk the next field as if it were an HWND since that works for both cases.
|
|
((LPMIXERCONTROLDETAILS)pMappedBuffer)->hwndOwner=(HWND)(UINT_PTR)((LPMIXERCONTROLDETAILS32)pMappedBuffer)->hwndOwner;
|
|
((LPMIXERCONTROLDETAILS)pMappedBuffer)->cChannels=((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cChannels;
|
|
((LPMIXERCONTROLDETAILS)pMappedBuffer)->dwControlID=((LPMIXERCONTROLDETAILS32)pMappedBuffer)->dwControlID;
|
|
((LPMIXERCONTROLDETAILS)pMappedBuffer)->cbStruct=((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cbStruct;
|
|
}
|
|
|
|
void
|
|
ThunkMixerControlDetails_Leave(
|
|
PVOID pMappedBuffer
|
|
)
|
|
{
|
|
// Now thunk the MIXERCONTROLDETAILS structure back to 32 bits.
|
|
// This is an IN PLACE thunk, so MUST be done from FIRST to LAST
|
|
// fields. Remember the order is different depending on direction!
|
|
|
|
((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cbStruct=((LPMIXERCONTROLDETAILS)pMappedBuffer)->cbStruct;
|
|
((LPMIXERCONTROLDETAILS32)pMappedBuffer)->dwControlID=((LPMIXERCONTROLDETAILS)pMappedBuffer)->dwControlID;
|
|
((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cChannels=((LPMIXERCONTROLDETAILS)pMappedBuffer)->cChannels;
|
|
// We always thunk the next field as if it were an HWND since that works for both cases.
|
|
((LPMIXERCONTROLDETAILS32)pMappedBuffer)->hwndOwner=(UINT32)(UINT_PTR)((LPMIXERCONTROLDETAILS)pMappedBuffer)->hwndOwner;
|
|
((LPMIXERCONTROLDETAILS32)pMappedBuffer)->cbDetails=((LPMIXERCONTROLDETAILS)pMappedBuffer)->cbDetails;
|
|
((LPMIXERCONTROLDETAILS32)pMappedBuffer)->paDetails=(UINT32)(UINT_PTR)((LPMIXERCONTROLDETAILS)pMappedBuffer)->paDetails;
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS
|
|
Dispatch_GetControlDetails(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo
|
|
)
|
|
{
|
|
PVOID paDetails = NULL;
|
|
PVOID paDetailsUnmapped;
|
|
DWORD dwSize;
|
|
PVOID pMappedBuffer;
|
|
NTSTATUS Status = STATUS_SUCCESS; // Assume success.
|
|
|
|
Status = ValidateAndCapture(pIrp,DeviceInfo,
|
|
#ifdef _WIN64
|
|
sizeof(MIXERCONTROLDETAILS32),
|
|
#endif
|
|
sizeof(MIXERCONTROLDETAILS), &pMappedBuffer);
|
|
if( !NT_SUCCESS(Status) )
|
|
{
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
goto Exit;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
ThunkMixerControlDetails_Enter(pMappedBuffer);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Pick reasonable max values for the data and number of controls to eliminate overflow
|
|
//
|
|
if ( ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails > 10000 ) ||
|
|
( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels > 100 ) ||
|
|
( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems > 100 ) )
|
|
{
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
ThunkMixerControlDetails_Leave(pMappedBuffer);
|
|
}
|
|
#endif
|
|
CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer);
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
//
|
|
// Map the array control details into system space.
|
|
//
|
|
paDetailsUnmapped = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->paDetails;
|
|
if( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems )
|
|
{
|
|
dwSize = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels *
|
|
((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems *
|
|
((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails;
|
|
|
|
} else {
|
|
dwSize = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels *
|
|
((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails;
|
|
}
|
|
|
|
try
|
|
{
|
|
ProbeForWrite(paDetailsUnmapped,
|
|
dwSize,
|
|
sizeof(DWORD));
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
ThunkMixerControlDetails_Leave(pMappedBuffer);
|
|
}
|
|
#endif
|
|
CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer);
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
Status = GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = CaptureBufferToLocalPool(paDetailsUnmapped,
|
|
dwSize,
|
|
&paDetails
|
|
#ifdef _WIN64
|
|
,0
|
|
#endif
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Call the handler.
|
|
//
|
|
Status = kmxlGetControlDetailsHandler(pContext,
|
|
DeviceInfo,
|
|
pMappedBuffer,
|
|
paDetails);
|
|
//
|
|
// The previous call should have set DeviceInfo->mmr and returned
|
|
// a valid Status value.
|
|
//
|
|
CopyAndFreeCapturedBuffer(paDetailsUnmapped,
|
|
dwSize,
|
|
&paDetails);
|
|
} else {
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
}
|
|
} else {
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp) && pMappedBuffer) {
|
|
ThunkMixerControlDetails_Leave(pMappedBuffer);
|
|
}
|
|
#endif
|
|
CopyAndFreeCapturedBuffer( DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer);
|
|
Exit:
|
|
//
|
|
// Always return the DEVICEINFO number of bytes from this call.
|
|
//
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
Dispatch_SetControlDetails(
|
|
PIRP pIrp,
|
|
PWDMACONTEXT pContext,
|
|
LPDEVICEINFO DeviceInfo
|
|
)
|
|
{
|
|
PVOID paDetails = NULL;
|
|
PVOID paDetailsUnmapped;
|
|
DWORD dwSize;
|
|
PVOID pMappedBuffer;
|
|
NTSTATUS Status = STATUS_SUCCESS; //Assume success.
|
|
|
|
Status = ValidateAndCapture(pIrp,DeviceInfo,
|
|
#ifdef _WIN64
|
|
sizeof(MIXERCONTROLDETAILS32),
|
|
#endif
|
|
sizeof(MIXERCONTROLDETAILS), &pMappedBuffer);
|
|
if( !NT_SUCCESS(Status) )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
// Now thunk the MIXERCONTROLDETAILS structure to 64 bits.
|
|
// This is an IN PLACE thunk, so MUST be done from last to first fields.
|
|
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
ThunkMixerControlDetails_Enter(pMappedBuffer);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Pick reasonable max values for the data and number of controls to eliminate overflow
|
|
//
|
|
if ( ( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails > 10000 ) ||
|
|
( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels > 100 ) ||
|
|
( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems > 100 ) )
|
|
{
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
ThunkMixerControlDetails_Leave(pMappedBuffer);
|
|
}
|
|
#endif
|
|
CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer);
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
//
|
|
// Map the array control details into system space.
|
|
//
|
|
paDetailsUnmapped = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->paDetails;
|
|
if( ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems )
|
|
{
|
|
dwSize = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels *
|
|
((LPMIXERCONTROLDETAILS) pMappedBuffer)->cMultipleItems *
|
|
((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails;
|
|
|
|
} else {
|
|
dwSize = ((LPMIXERCONTROLDETAILS) pMappedBuffer)->cChannels *
|
|
((LPMIXERCONTROLDETAILS) pMappedBuffer)->cbDetails;
|
|
}
|
|
|
|
try
|
|
{
|
|
ProbeForRead(((LPMIXERCONTROLDETAILS) pMappedBuffer)->paDetails,
|
|
dwSize,
|
|
sizeof(DWORD));
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
ThunkMixerControlDetails_Leave(pMappedBuffer);
|
|
}
|
|
#endif
|
|
CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer);
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
Status = GetExceptionCode();
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = CaptureBufferToLocalPool(paDetailsUnmapped,
|
|
dwSize,
|
|
&paDetails
|
|
#ifdef _WIN64
|
|
,0
|
|
#endif
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Call the handler.
|
|
//
|
|
Status = kmxlSetControlDetailsHandler(pContext,
|
|
DeviceInfo,
|
|
pMappedBuffer,
|
|
paDetails,
|
|
MIXER_FLAG_PERSIST );
|
|
//
|
|
// The previous call should have set DeviceInfo->mmr and returned
|
|
// a valid Status value.
|
|
//
|
|
|
|
CopyAndFreeCapturedBuffer(paDetailsUnmapped,
|
|
dwSize,
|
|
&paDetails);
|
|
} else {
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
}
|
|
} else {
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp) && pMappedBuffer) {
|
|
ThunkMixerControlDetails_Leave(pMappedBuffer);
|
|
}
|
|
#endif
|
|
CopyAndFreeCapturedBuffer(DeviceInfo->DataBuffer,
|
|
DeviceInfo->DataBufferSize,
|
|
&pMappedBuffer);
|
|
|
|
Exit:
|
|
//
|
|
// Always return sizeof(DEVICEINFO) for this call.
|
|
//
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Dispatch_GetHardwareEventData(
|
|
PIRP pIrp,
|
|
LPDEVICEINFO DeviceInfo
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Always return sizeof(DEVICEINFO) for this call.
|
|
//
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
|
|
if (DeviceInfo->DataBufferSize != 0)
|
|
{
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
GetHardwareEventData(DeviceInfo);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SoundDispatch(
|
|
IN PDEVICE_OBJECT pDO,
|
|
IN PIRP pIrp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Driver dispatch routine. Processes IRPs based on IRP MajorFunction
|
|
|
|
Arguments:
|
|
pDO -- pointer to the device object
|
|
pIrp -- pointer to the IRP to process
|
|
|
|
Return Value:
|
|
Returns the value of the IRP IoStatus.Status
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
PWDMACONTEXT pContext;
|
|
LPDEVICEINFO DeviceInfo;
|
|
#ifdef _WIN64
|
|
LPDEVICEINFO32 DeviceInfo32=NULL;
|
|
LOCALDEVICEINFO LocalDeviceInfo;
|
|
#endif
|
|
LPVOID DataBuffer;
|
|
DWORD DataBufferSize;
|
|
ULONG IoCode;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
//
|
|
// Get the CurrentStackLocation and log it so we know what is going on
|
|
//
|
|
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
|
IoCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
|
|
pContext = pIrpStack->FileObject->FsContext;
|
|
ASSERT(pContext);
|
|
|
|
ASSERT(pIrpStack->MajorFunction != IRP_MJ_CREATE &&
|
|
pIrpStack->MajorFunction != IRP_MJ_CLOSE);
|
|
|
|
//
|
|
// Can't assume that FsContext is initialized if the device has
|
|
// been opened with FO_DIRECT_DEVICE_OPEN
|
|
//
|
|
if (pIrpStack->FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
|
|
{
|
|
DPF(DL_TRACE|FA_IOCTL, ("IRP_MJ_DEVICE_CONTROL: Opened with FO_DIRECT_DEVICE_OPEN, no device context") );
|
|
|
|
return KsDefaultDeviceIoCompletion(pDO, pIrp);
|
|
}
|
|
|
|
Status = ValidateIrp(pIrp);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
pIrp->IoStatus.Status = Status;
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
RETURN( Status );
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
DeviceInfo32=((LPDEVICEINFO32)pIrp->AssociatedIrp.SystemBuffer);
|
|
RtlZeroMemory(&LocalDeviceInfo, sizeof(LOCALDEVICEINFO));
|
|
DeviceInfo=&LocalDeviceInfo.DeviceInfo;
|
|
ThunkDeviceInfo3264(DeviceInfo32, DeviceInfo);
|
|
} else {
|
|
#endif
|
|
DeviceInfo = ((LPDEVICEINFO)pIrp->AssociatedIrp.SystemBuffer);
|
|
#ifdef _WIN64
|
|
}
|
|
#endif
|
|
DataBufferSize = DeviceInfo->DataBufferSize;
|
|
|
|
WdmaGrabMutex(pContext);
|
|
|
|
switch (pIrpStack->MajorFunction)
|
|
{
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
{
|
|
switch (IoCode)
|
|
{
|
|
case IOCTL_WDMAUD_INIT:
|
|
DPF( DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_INIT"));
|
|
if (DataBufferSize != 0)
|
|
{
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
break;
|
|
}
|
|
|
|
WdmaReleaseMutex(pContext);
|
|
|
|
//
|
|
// If sysaudio fails to load, the device interface
|
|
// will be disabled and the SysAudioPnPNotification
|
|
// will not be called anymore until the sysaudio
|
|
// device interface is reenabled.
|
|
//
|
|
if ( IsSysaudioInterfaceActive() )
|
|
{
|
|
KeWaitForSingleObject(&pContext->InitializedSysaudioEvent,
|
|
Executive, KernelMode, FALSE, NULL);
|
|
|
|
// This could happen if there was an error in InitializeSysaudio or
|
|
// the memory allocation failed in QueueWorkList
|
|
if (pContext->fInitializeSysaudio == FALSE)
|
|
{
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
DPF(DL_WARNING|FA_IOCTL, ("IOCTL_WDMAUD_INIT: Didn't init sysaudio! Failing IOCTL_WDMAUD_INIT: %08x", Status));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
DPF(DL_WARNING|FA_IOCTL, ("IOCTL_WDMAUD_INIT: Sysaudio Device interface disabled! Failing IOCTL_WDMAUD_INIT: %08x", Status));
|
|
}
|
|
|
|
WdmaGrabMutex(pContext);
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_EXIT:
|
|
if (DataBufferSize != 0)
|
|
{
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
break;
|
|
}
|
|
|
|
DPF( DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_EXIT"));
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_ADD_DEVNODE:
|
|
{
|
|
DPF( DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_ADD_DEVNODE"));
|
|
if (DataBufferSize != 0)
|
|
{
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
break;
|
|
}
|
|
DPF(DL_TRACE|FA_INSTANCE,("pContext=%08X, DI=%08X DeviceType=%08X",
|
|
pContext,
|
|
DeviceInfo->wstrDeviceInterface,
|
|
DeviceInfo->DeviceType) );
|
|
Status=AddDevNode(pContext, DeviceInfo->wstrDeviceInterface, DeviceInfo->DeviceType);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_WDMAUD_REMOVE_DEVNODE:
|
|
{
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_REMOVE_DEVNODE"));
|
|
if (DataBufferSize != 0)
|
|
{
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
break;
|
|
}
|
|
RemoveDevNode(pContext, DeviceInfo->wstrDeviceInterface, DeviceInfo->DeviceType);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_WDMAUD_GET_CAPABILITIES:
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_GET_CAPABILITIES"));
|
|
|
|
Status = Dispatch_GetCapabilities(pIrp,pContext,
|
|
DeviceInfo);
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_GET_NUM_DEVS:
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_GET_NUM_DEVS"));
|
|
if (DataBufferSize != 0)
|
|
{
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
break;
|
|
}
|
|
|
|
Status = wdmaudGetNumDevs(pContext,
|
|
DeviceInfo->DeviceType,
|
|
DeviceInfo->wstrDeviceInterface,
|
|
&DeviceInfo->DeviceNumber);
|
|
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
|
|
DeviceInfo->mmr=MMSYSERR_NOERROR;
|
|
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_SET_PREFERRED_DEVICE:
|
|
DPF(DL_TRACE|FA_IOCTL,
|
|
("IOCTL_WDMAUD_SET_PREFERRED_DEVICE %d",
|
|
DeviceInfo->DeviceNumber));
|
|
|
|
Status = SetPreferredDevice(pContext, DeviceInfo);
|
|
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_OPEN_PIN:
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_OPEN_PIN"));
|
|
|
|
UpdatePreferredDevice(pContext);
|
|
|
|
Status = Dispatch_OpenPin(pIrp,
|
|
pContext,
|
|
DeviceInfo);
|
|
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_CLOSE_PIN:
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_CLOSE_PIN"));
|
|
|
|
Status = Dispatch_ClosePin(pIrp,
|
|
pContext,
|
|
DeviceInfo);
|
|
|
|
break;
|
|
|
|
|
|
//
|
|
// WaveOut, wavein, midiout and midiin routines
|
|
//
|
|
|
|
case IOCTL_WDMAUD_WAVE_OUT_PAUSE:
|
|
case IOCTL_WDMAUD_WAVE_OUT_PLAY:
|
|
case IOCTL_WDMAUD_WAVE_OUT_RESET:
|
|
case IOCTL_WDMAUD_WAVE_OUT_BREAKLOOP:
|
|
case IOCTL_WDMAUD_WAVE_IN_STOP:
|
|
case IOCTL_WDMAUD_WAVE_IN_RECORD:
|
|
case IOCTL_WDMAUD_WAVE_IN_RESET:
|
|
case IOCTL_WDMAUD_MIDI_OUT_RESET:
|
|
case IOCTL_WDMAUD_MIDI_OUT_WRITE_DATA:
|
|
case IOCTL_WDMAUD_MIDI_IN_STOP:
|
|
case IOCTL_WDMAUD_MIDI_IN_RECORD:
|
|
case IOCTL_WDMAUD_MIDI_IN_RESET:
|
|
Status = Dispatch_State(pIrp,
|
|
pContext,
|
|
DeviceInfo,
|
|
IoCode);
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_WAVE_OUT_GET_POS:
|
|
case IOCTL_WDMAUD_WAVE_IN_GET_POS:
|
|
Status = Dispatch_WaveGetPos(pIrp,pContext,
|
|
DeviceInfo,IoCode);
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_GET_VOLUME:
|
|
case IOCTL_WDMAUD_WAVE_OUT_GET_VOLUME:
|
|
case IOCTL_WDMAUD_MIDI_OUT_GET_VOLUME:
|
|
Status = Dispatch_GetVolume(pIrp,pContext,
|
|
DeviceInfo,IoCode);
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_SET_VOLUME:
|
|
case IOCTL_WDMAUD_WAVE_OUT_SET_VOLUME:
|
|
case IOCTL_WDMAUD_MIDI_OUT_SET_VOLUME:
|
|
Status = Dispatch_SetVolume(pIrp,pContext,
|
|
DeviceInfo,IoCode);
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN:
|
|
{
|
|
BOOL bCompletedIrp = FALSE;
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN"));
|
|
|
|
Status = Dispatch_WaveOutWritePin(pIrp,pContext,
|
|
DeviceInfo,&bCompletedIrp);
|
|
if( bCompletedIrp )
|
|
{
|
|
//
|
|
// !!! NOTE: Must return here so that we don't call IoCompleteRequest later !!!
|
|
//
|
|
WdmaReleaseMutex(pContext);
|
|
|
|
// For 32 bit irps we do NOT need to thunk DeviceInfo back to 32 bits, since
|
|
// nothing in this case statement has written anything into the DeviceInfo
|
|
// structure. If thunking back is ever required, make sure to NOT touch a
|
|
// potentially already completed irp. WriteWaveOutPin now completes the irp
|
|
// in some cases.
|
|
|
|
return Status ;
|
|
}
|
|
//
|
|
// If there was some problem trying to schedule the Irp we will
|
|
// end up here. bCompleteIrp will still be FALSE indicating that
|
|
// we need to complete the Irp. So, we break out of the switch
|
|
// statement, endin up at the end of SoundDispatch perform cleanup
|
|
// and complete the Irp.
|
|
//
|
|
}
|
|
break;
|
|
|
|
//
|
|
// WaveIn routines
|
|
//
|
|
|
|
case IOCTL_WDMAUD_WAVE_IN_READ_PIN:
|
|
{
|
|
BOOL bCompletedIrp = FALSE;
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_WAVE_IN_READ_PIN"));
|
|
|
|
Status = Dispatch_WaveInReadPin(pIrp,pContext,
|
|
DeviceInfo,&bCompletedIrp);
|
|
if( bCompletedIrp )
|
|
{
|
|
//
|
|
// Don't need the lock any longer.
|
|
//
|
|
WdmaReleaseMutex(pContext);
|
|
|
|
return Status;
|
|
}
|
|
|
|
// For 32 bit irps we do NOT need to thunk DeviceInfo back to 32 bits, since
|
|
// nothing in this case statement has written anything into the DeviceInfo
|
|
// structure. If thunking back is ever required, make sure to NOT touch a
|
|
// potentially already completed irp. ReadWaveInPin now completes the irp
|
|
// in some cases.
|
|
//
|
|
// If there was some problem trying to schedule the Irp we will
|
|
// end up here. bCompleteIrp will still be FALSE indicating that
|
|
// we need to complete the Irp. So, we break out of the switch
|
|
// statement, endin up at the end of SoundDispatch perform cleanup
|
|
// and complete the Irp.
|
|
//
|
|
}
|
|
break;
|
|
//
|
|
// MidiOut routines
|
|
//
|
|
|
|
case IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA:
|
|
{
|
|
BOOL bCompletedIrp = FALSE;
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIDI_OUT_WRITE_LONGDATA"));
|
|
|
|
Status = Dispatch_MidiOutWriteLongdata(pIrp,
|
|
pContext,
|
|
DeviceInfo,
|
|
&bCompletedIrp);
|
|
|
|
//
|
|
// If it was completed already, don't do it again!
|
|
//
|
|
if( bCompletedIrp )
|
|
{
|
|
//
|
|
// Don't need the lock any longer.
|
|
//
|
|
WdmaReleaseMutex(pContext);
|
|
|
|
// For 32 bit irps we do NOT need to thunk DeviceInfo back to 32 bits, since
|
|
// nothing in this case statement has written anything into the DeviceInfo
|
|
// structure. If thunking back is ever required, make sure to NOT touch a
|
|
// potentially already completed irp. wdmaudUnprepareIrp now completes the irp
|
|
// in most cases.
|
|
return Status;
|
|
}
|
|
//
|
|
// If there was some problem trying to schedule the Irp we will
|
|
// end up here. bCompleteIrp will still be FALSE indicating that
|
|
// we need to complete the Irp. So, we break out of the switch
|
|
// statement, endin up at the end of SoundDispatch perform cleanup
|
|
// and complete the Irp.
|
|
//
|
|
}
|
|
break;
|
|
|
|
//
|
|
// MidiIn routines
|
|
//
|
|
//
|
|
// Buffers for recording MIDI messages...
|
|
//
|
|
case IOCTL_WDMAUD_MIDI_IN_READ_PIN:
|
|
{
|
|
BOOL bCompletedIrp = FALSE;
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIDI_IN_READ_PIN"));
|
|
|
|
Status = Dispatch_MidiInReadPin(pIrp,pContext,
|
|
DeviceInfo,&bCompletedIrp);
|
|
//
|
|
// If it was completed already, don't do it again!
|
|
//
|
|
if( bCompletedIrp )
|
|
{
|
|
//
|
|
// Don't need the lock any longer.
|
|
//
|
|
WdmaReleaseMutex(pContext);
|
|
|
|
// For 32 bit irps we do NOT need to thunk DeviceInfo back to 32 bits, since
|
|
// nothing in this case statement has written anything into the DeviceInfo
|
|
// structure. If thunking back is ever required, make sure to NOT touch a
|
|
// potentially already completed irp. wdmaudUnprepareIrp now completes the irp
|
|
// in most cases.
|
|
return Status;
|
|
}
|
|
//
|
|
// If there was some problem trying to schedule the Irp we will
|
|
// end up here. bCompleteIrp will still be FALSE indicating that
|
|
// we need to complete the Irp. So, we break out of the switch
|
|
// statement, endin up at the end of SoundDispatch perform cleanup
|
|
// and complete the Irp.
|
|
//
|
|
}
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_MIXER_OPEN:
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_OPEN"));
|
|
{
|
|
extern PKEVENT pHardwareCallbackEvent;
|
|
|
|
if (DataBufferSize != 0)
|
|
{
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
break;
|
|
}
|
|
|
|
if (pHardwareCallbackEvent==NULL && DeviceInfo->HardwareCallbackEventHandle) {
|
|
Status = ObReferenceObjectByHandle(DeviceInfo->HardwareCallbackEventHandle, EVENT_ALL_ACCESS, *ExEventObjectType, pIrp->RequestorMode, (PVOID *)&pHardwareCallbackEvent, NULL);
|
|
if (Status!=STATUS_SUCCESS) {
|
|
DPF(DL_WARNING|FA_IOCTL, ("Could not reference hardware callback event object!"));
|
|
}
|
|
}
|
|
|
|
Status = kmxlOpenHandler( pContext, DeviceInfo, NULL );
|
|
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
}
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_MIXER_CLOSE:
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_CLOSE"));
|
|
if (DataBufferSize != 0)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
DeviceInfo->mmr = MMSYSERR_INVALPARAM;
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
break;
|
|
}
|
|
|
|
Status = kmxlCloseHandler( DeviceInfo, NULL );
|
|
|
|
pIrp->IoStatus.Information = sizeof(DEVICEINFO);
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_MIXER_GETLINEINFO:
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_GETLINEINFO"));
|
|
|
|
Status = Dispatch_GetLineInfo(pIrp,
|
|
pContext,
|
|
DeviceInfo);
|
|
break;
|
|
|
|
case IOCTL_WDMAUD_MIXER_GETLINECONTROLS:
|
|
{
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_GETLINECONTROLS"));
|
|
|
|
Status = Dispatch_GetLineControls(pIrp,
|
|
pContext,
|
|
DeviceInfo);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS:
|
|
{
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS"));
|
|
Status = Dispatch_GetControlDetails(pIrp,
|
|
pContext,
|
|
DeviceInfo);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS:
|
|
{
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS"));
|
|
Status = Dispatch_SetControlDetails(pIrp,
|
|
pContext,
|
|
DeviceInfo);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA:
|
|
{
|
|
DPF(DL_TRACE|FA_IOCTL, ("IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA"));
|
|
Status = Dispatch_GetHardwareEventData(pIrp,
|
|
DeviceInfo);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
} // end of switch on IOCTL
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
} // end of switch on IRP_MAJOR_XXXX
|
|
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess(pIrp)) {
|
|
if (DeviceInfo32!=NULL) {
|
|
ThunkDeviceInfo6432(DeviceInfo, DeviceInfo32);
|
|
}
|
|
else {
|
|
DPF(DL_WARNING|FA_IOCTL,("DeviceInfo32") );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Now complete the IRP
|
|
//
|
|
pIrp->IoStatus.Status = Status;
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
|
|
WdmaReleaseMutex(pContext);
|
|
|
|
RETURN( Status );
|
|
}
|
|
|
|
|