windows-nt/Source/XPSP1/NT/drivers/wdm/audio/legacy/wdmaud.sys/device.c

340 lines
9.6 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/****************************************************************************
*
* device.c
*
* Kernel mode entry point for WDM drivers
*
* Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
*
* History
* S.Mohanraj (MohanS)
* M.McLaughlin (MikeM)
* 5-19-97 - Noel Cross (NoelC)
*
***************************************************************************/
#define IRPMJFUNCDESC
#include "wdmsys.h"
KMUTEX wdmaMutex;
KMUTEX mtxNote;
LIST_ENTRY WdmaContextListHead;
KMUTEX WdmaContextListMutex;
//
// For hardware notifications, we need to init these two values.
//
extern KSPIN_LOCK HardwareCallbackSpinLock;
extern LIST_ENTRY HardwareCallbackListHead;
extern PKSWORKER HardwareCallbackWorkerObject;
extern WORK_QUEUE_ITEM HardwareCallbackWorkItem;
//VOID kmxlPersistHWControlWorker(VOID);
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
NTSTATUS AddFsContextToList(PWDMACONTEXT pWdmaContext)
{
NTSTATUS Status;
PAGED_CODE();
KeEnterCriticalRegion();
Status = KeWaitForMutexObject(&WdmaContextListMutex, Executive, KernelMode,
FALSE, NULL);
if (NT_SUCCESS(Status))
{
InsertTailList(&WdmaContextListHead, &pWdmaContext->Next);
KeReleaseMutex(&WdmaContextListMutex, FALSE);
}
pWdmaContext->fInList = NT_SUCCESS(Status);
KeLeaveCriticalRegion();
RETURN( Status );
}
NTSTATUS RemoveFsContextFromList(PWDMACONTEXT pWdmaContext)
{
NTSTATUS Status;
PAGED_CODE();
if (pWdmaContext->fInList) {
KeEnterCriticalRegion();
Status = KeWaitForMutexObject(&WdmaContextListMutex, Executive,
KernelMode, FALSE, NULL);
if (NT_SUCCESS(Status)) {
RemoveEntryList(&pWdmaContext->Next);
KeReleaseMutex(&WdmaContextListMutex, FALSE);
}
KeLeaveCriticalRegion();
} else {
Status = STATUS_SUCCESS;
}
RETURN( Status );
}
//
// This routine walks the list of global context structures and calls the callback
// routine with the structure. If the callback routine returns STATUS_MORE_DATA
// the routine will keep on searching the list. If it returns an error or success
// the search will end.
//
NTSTATUS
EnumFsContext(
FNCONTEXTCALLBACK fnCallback,
PVOID pvoidRefData,
PVOID pvoidRefData2
)
{
NTSTATUS Status;
PLIST_ENTRY ple;
PWDMACONTEXT pContext;
PAGED_CODE();
//
// Make sure that we can walk are list without being interrupted.
//
KeEnterCriticalRegion();
Status = KeWaitForMutexObject(&WdmaContextListMutex, Executive,
KernelMode, FALSE, NULL);
if (NT_SUCCESS(Status))
{
//
// Walk the list here and call the callback routine.
//
for(ple = WdmaContextListHead.Flink;
ple != &WdmaContextListHead;
ple = ple->Flink)
{
pContext = CONTAINING_RECORD(ple, WDMACONTEXT, Next);
//
// The callback routine will return STATUS_MORE_ENTRIES
// if it's not done.
//
DPF(DL_TRACE|FA_USER,( "Calling fnCallback: %x %x",pvoidRefData,pvoidRefData2 ) );
Status = fnCallback(pContext,pvoidRefData,pvoidRefData2);
if( STATUS_MORE_ENTRIES != Status )
{
break;
}
}
//
// "break;" should bring us here to release our locks.
//
KeReleaseMutex(&WdmaContextListMutex, FALSE);
} else {
DPF(DL_WARNING|FA_USER,( "Failed to get Mutex: %x %x",pvoidRefData,pvoidRefData2 ) );
}
KeLeaveCriticalRegion();
//
// If the callback routine doesn't return a NTSTATUS, it didn't find
// what it was looking for, thus, EnumFsContext returns as error.
//
if( STATUS_MORE_ENTRIES == Status )
{
Status = STATUS_UNSUCCESSFUL;
}
DPF(DL_TRACE|FA_USER,( "Returning Status: %x",Status ) );
return Status;
}
NTSTATUS DriverEntry
(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING usRegistryPathName
)
{
NTSTATUS Status;
PAGED_CODE();
#ifdef DEBUG
GetuiDebugLevel();
#endif
DPF(DL_TRACE|FA_ALL, ("************************************************************") );
DPF(DL_TRACE|FA_ALL, ("* uiDebugLevel=%08X controls the debug output. To change",uiDebugLevel) );
DPF(DL_TRACE|FA_ALL, ("* edit uiDebugLevel like: e uidebuglevel and set to ") );
DPF(DL_TRACE|FA_ALL, ("* 0 - show only fatal error messages and asserts ") );
DPF(DL_TRACE|FA_ALL, ("* 1 (Default) - Also show non-fatal errors and return codes ") );
DPF(DL_TRACE|FA_ALL, ("* 2 - Also show trace messages ") );
DPF(DL_TRACE|FA_ALL, ("* 4 - Show Every message ") );
DPF(DL_TRACE|FA_ALL, ("************************************************************") );
DriverObject->DriverExtension->AddDevice = PnpAddDevice;
DriverObject->DriverUnload = PnpDriverUnload; // KsNullDriverUnload;
DriverObject->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower;
DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp;
DriverObject->MajorFunction[IRP_MJ_CREATE] = SoundDispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SoundDispatchClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SoundDispatch;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SoundDispatchCleanup;
KeInitializeMutex(&wdmaMutex, 0);
KeInitializeMutex(&mtxNote, 0);
//
// Initialize the hardware event items
//
InitializeListHead(&HardwareCallbackListHead);
KeInitializeSpinLock(&HardwareCallbackSpinLock);
ExInitializeWorkItem(&HardwareCallbackWorkItem,
(PWORKER_THREAD_ROUTINE)kmxlPersistHWControlWorker,
(PVOID)NULL); //pnnode
Status = KsRegisterWorker( DelayedWorkQueue, &HardwareCallbackWorkerObject );
if (!NT_SUCCESS(Status))
{
DPFBTRAP();
HardwareCallbackWorkerObject = NULL;
}
return STATUS_SUCCESS;
}
NTSTATUS
DispatchPnp(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
PIO_STACK_LOCATION pIrpStack;
PAGED_CODE();
pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
switch(pIrpStack->MinorFunction) {
case IRP_MN_QUERY_PNP_DEVICE_STATE:
//
// Mark the device as not disableable.
//
pIrp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
break;
}
return(KsDefaultDispatchPnp(pDeviceObject, pIrp));
}
NTSTATUS
PnpAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
When a new device is detected, PnP calls this entry point with the
new PhysicalDeviceObject (PDO). The driver creates an associated
FunctionalDeviceObject (FDO).
Arguments:
DriverObject -
Pointer to the driver object.
PhysicalDeviceObject -
Pointer to the new physical device object.
Return Values:
STATUS_SUCCESS or an appropriate error condition.
--*/
{
NTSTATUS Status;
PDEVICE_OBJECT FunctionalDeviceObject;
PDEVICE_INSTANCE pDeviceInstance;
PAGED_CODE();
DPF(DL_TRACE|FA_ALL, ("Entering"));
//
// The Software Bus Enumerator expects to establish links
// using this device name.
//
Status = IoCreateDevice(
DriverObject,
sizeof( DEVICE_INSTANCE ),
NULL, // FDOs are unnamed
FILE_DEVICE_KS,
0,
FALSE,
&FunctionalDeviceObject );
if (!NT_SUCCESS(Status)) {
RETURN( Status );
}
pDeviceInstance = (PDEVICE_INSTANCE)FunctionalDeviceObject->DeviceExtension;
Status = KsAllocateDeviceHeader(
&pDeviceInstance->pDeviceHeader,
0,
NULL );
if (NT_SUCCESS(Status))
{
KsSetDevicePnpAndBaseObject(
pDeviceInstance->pDeviceHeader,
IoAttachDeviceToDeviceStack(
FunctionalDeviceObject,
PhysicalDeviceObject ),
FunctionalDeviceObject );
FunctionalDeviceObject->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE);
FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
}
else
{
IoDeleteDevice( FunctionalDeviceObject );
}
#ifdef PROFILE
WdmaInitProfile();
#endif
InitializeListHead(&WdmaContextListHead);
KeInitializeMutex(&WdmaContextListMutex, 0);
InitializeListHead(&wdmaPendingIrpQueue.WdmaPendingIrpListHead);
KeInitializeSpinLock(&wdmaPendingIrpQueue.WdmaPendingIrpListSpinLock);
IoCsqInitialize( &wdmaPendingIrpQueue.Csq,
WdmaCsqInsertIrp,
WdmaCsqRemoveIrp,
WdmaCsqPeekNextIrp,
WdmaCsqAcquireLock,
WdmaCsqReleaseLock,
WdmaCsqCompleteCanceledIrp );
RETURN( Status );
}
VOID
PnpDriverUnload(
IN PDRIVER_OBJECT DriverObject
)
{
PAGED_CODE();
DPF(DL_TRACE|FA_ALL,("Entering"));
//
// Wait for all or our scheduled work items to complete.
//
if( HardwareCallbackWorkerObject )
{
KsUnregisterWorker( HardwareCallbackWorkerObject );
HardwareCallbackWorkerObject = NULL;
}
kmxlCleanupNoteList();
}