|
|
/****************************************************************************
* * 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. But only if we marked the IRP as pending.
// All other return codes should be handled normally.
//
#ifdef DEBUG
if( *pCompletedIrp ) { ASSERT(Status == STATUS_PENDING); } #endif
} } } 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 ); }
|