|
|
/****************************************************************************
* * 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(); }
|