|
|
/*++
Copyright (C) Microsoft Corporation, 1996 - 1999
Module Name:
bdl.c
Abstract:
This module contains the implementation for the Microsoft Biometric Device Library
Environment:
Kernel mode only.
Notes:
Revision History:
- Created May 2002 by Reid Kuhn
--*/
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <strsafe.h>
#include <wdm.h>
#include "bdlint.h"
#ifndef FILE_DEVICE_BIOMETRIC
#define FILE_DEVICE_BIOMETRIC 0x3B
#endif
#define BDL_DRIVER_EXTENSION_ID ((PVOID) 1)
typedef enum _IRP_ACTION { Undefined = 0, SkipRequest, WaitForCompletion, CompleteRequest, MarkPending
} IRP_ACTION;
typedef struct _POWER_IRP_CONTEXT { PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension; PIRP pIrp; UCHAR MinorFunction;
} POWER_IRP_CONTEXT, *PPOWER_IRP_CONTEXT;
VOID BDLControlChangeDpc ( IN PKDPC pDpc, IN PVOID pvContext, IN PVOID pArg1, IN PVOID pArg2 );
/////////////////////////////////////////////////////////////////////////////////////////
//
// Forward declarations of all the PNP and Power handling functions.
//
NTSTATUS BDLPnPStart ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp, PIO_STACK_LOCATION pStackLocation );
NTSTATUS BDLPnPQueryStop ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp );
NTSTATUS BDLPnPCancelStop ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp );
NTSTATUS BDLPnPStop ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp );
NTSTATUS BDLPnPQueryRemove ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp );
NTSTATUS BDLPnPCancelRemove ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp );
NTSTATUS BDLHandleRemove ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp );
NTSTATUS BDLPnPRemove ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pDeviceObject, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp );
NTSTATUS BDLPnPSurpriseRemoval ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp );
NTSTATUS BDLSystemQueryPower ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PIO_STACK_LOCATION pStackLocation, OUT IRP_ACTION *pIRPAction, OUT PIO_COMPLETION_ROUTINE *pIoCompletionRoutine );
NTSTATUS BDLSystemSetPower ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PIO_STACK_LOCATION pStackLocation, OUT IRP_ACTION *pIRPAction, OUT PIO_COMPLETION_ROUTINE *pIoCompletionRoutine );
NTSTATUS BDLDeviceQueryPower ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PIO_STACK_LOCATION pStackLocation, OUT IRP_ACTION *pIRPAction, OUT PIO_COMPLETION_ROUTINE *pIoCompletionRoutine );
NTSTATUS BDLDeviceSetPower ( IN PDEVICE_OBJECT pDeviceObject, IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PIO_STACK_LOCATION pStackLocation, OUT IRP_ACTION *pIRPAction, OUT PIO_COMPLETION_ROUTINE *pIoCompletionRoutine );
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGEABLE, BDLDriverUnload)
#pragma alloc_text(PAGEABLE, BDLAddDevice)
//
// This is the main driver entry point
//
NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!DriverEntry\n", __DATE__, __TIME__))
return (STATUS_SUCCESS); }
/////////////////////////////////////////////////////////////////////////////////////////
//
// These functions are the BDL's entry points for all the major system IRPs
//
//
// BDLDriverUnload()
//
// The driver unload routine. This is called by the I/O system
// when the device is unloaded from memory.
//
// PARAMETERS:
// pDriverObject Pointer to driver object created by system.
//
// RETURNS:
// STATUS_SUCCESS If the BDLDriverUnload call succeeded
//
VOID BDLDriverUnload ( IN PDRIVER_OBJECT pDriverObject ) { BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLDriverUnload: Enter\n", __DATE__, __TIME__))
PAGED_CODE();
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLDriverUnload: Leave\n", __DATE__, __TIME__)) }
//
// BDLCreate()
//
// This routine is called by the I/O system when the device is opened
//
// PARAMETERS:
// pDeviceObject Pointer to device object for this miniport
// pIrp The IRP that represents this call
//
NTSTATUS BDLCreate ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS; PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension = pDeviceObject->DeviceExtension;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLCreate: Enter\n", __DATE__, __TIME__))
status = IoAcquireRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) 'lCrC');
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLCreate: IoAcquireRemoveLock failed with %lx\n", __DATE__, __TIME__, status)) }
if (InterlockedCompareExchange(&(pBDLExtension->DeviceOpen), TRUE, FALSE) == FALSE) { BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLCreate: Device opened\n", __DATE__, __TIME__)) } else { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLCreate: device is already open\n", __DATE__, __TIME__))
//
// The device is already in use, so fail the call
//
status = STATUS_UNSUCCESSFUL;
//
// release the lock since we are failing the call
//
IoReleaseRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) 'lCrC'); }
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLCreate: Leave\n", __DATE__, __TIME__))
return (status); }
//
// BDLClose()
//
// This routine is called by the I/O system when the device is closed
//
NTSTATUS BDLClose ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension = pDeviceObject->DeviceExtension;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLClose: Enter\n", __DATE__, __TIME__))
//
// Clean up any outstanding notification info and data handles
//
BDLCleanupNotificationStruct(pBDLExtension); BDLCleanupDataHandles(pBDLExtension);
IoReleaseRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) 'lCrC'); pBDLExtension->DeviceOpen = FALSE;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLClose: Leave\n", __DATE__, __TIME__))
return (STATUS_SUCCESS); }
//
// BDLCleanup()
//
// This routine is called when the calling application terminates
//
NTSTATUS BDLCleanup ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension = pDeviceObject->DeviceExtension;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLCleanup: Enter\n", __DATE__, __TIME__))
//
// Clean up any outstanding notification info and data handles
//
BDLCleanupNotificationStruct(pBDLExtension); BDLCleanupDataHandles(pBDLExtension);
//
// Cancel the notification IRP (probably don't have to do this, since the
// system should call the cancel routine on the applications behalf.
//
BDLCancelGetNotificationIRP(pBDLExtension);
//
// Complete this IRP
//
pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(pIrp, IO_NO_INCREMENT);
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLCleanup: Leave\n", __DATE__, __TIME__))
return (STATUS_SUCCESS); }
//
// BDLDeviceControl()
//
// This routine is called when an IOCTL is made on this device
//
NTSTATUS BDLDeviceControl ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS; PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension = pDeviceObject->DeviceExtension; PIO_STACK_LOCATION pStack = NULL; ULONG cbIn = 0; ULONG cbOut = 0; ULONG IOCTLCode = 0; PVOID pIOBuffer = NULL; ULONG cbOutUsed = 0; KIRQL irql;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLDeviceControl: Enter\n", __DATE__, __TIME__)) //
// Do some checking that is valid for all IOCTLs
//
//
// Acquire the remove lock and check to make sure the device wasn't removed
//
status = IoAcquireRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) 'tCoI');
if (status != STATUS_SUCCESS) { //
// The device has been removed, so fail the call.
//
pIrp->IoStatus.Information = 0; status = STATUS_DEVICE_REMOVED; goto Return; } KeAcquireSpinLock(&(pBDLExtension->SpinLock), &irql);
//
// If IO count is anything other than 0 than the device must already
// be started so just incremement the IO count. If it is 0, then wait
// on the started event to make sure the device is started.
//
if (pBDLExtension->IoCount == 0) { KeReleaseSpinLock(&(pBDLExtension->SpinLock), irql);
status = KeWaitForSingleObject( &(pBDLExtension->DeviceStartedEvent), Executive, KernelMode, FALSE, NULL);
ASSERT(status == STATUS_SUCCESS);
KeAcquireSpinLock(&(pBDLExtension->SpinLock), &irql); }
pBDLExtension->IoCount++; KeReleaseSpinLock(&(pBDLExtension->SpinLock), irql);
//
// If the device has been removed then fail the call. This will happen
// if the device is stopped and the IOCTL is blocked at the above
// KeWaitForSingleObject and then the device gets removed.
//
if (pBDLExtension->fDeviceRemoved == TRUE) { status = STATUS_DEVICE_REMOVED; goto Return; }
//
// Get the input/output buffer, buffer sizes, and control code
//
pStack = IoGetCurrentIrpStackLocation(pIrp); cbIn = pStack->Parameters.DeviceIoControl.InputBufferLength; cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength; IOCTLCode = pStack->Parameters.DeviceIoControl.IoControlCode; pIOBuffer = pIrp->AssociatedIrp.SystemBuffer;
//
// We must run at passive level otherwise IoCompleteRequest won't work properly
//
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
//
// Now, do the IOCTL specific processing
//
switch (IOCTLCode) { case BDD_IOCTL_STARTUP:
status = BDLIOCTL_Startup(pBDLExtension, cbIn, cbOut, pIOBuffer, &cbOutUsed); break;
case BDD_IOCTL_SHUTDOWN:
status = BDLIOCTL_Shutdown(pBDLExtension, cbIn, cbOut, pIOBuffer, &cbOutUsed); break;
case BDD_IOCTL_GETDEVICEINFO:
status = BDLIOCTL_GetDeviceInfo(pBDLExtension, cbIn, cbOut, pIOBuffer, &cbOutUsed); break;
case BDD_IOCTL_DOCHANNEL:
status = BDLIOCTL_DoChannel(pBDLExtension, cbIn, cbOut, pIOBuffer, &cbOutUsed); break;
case BDD_IOCTL_GETCONTROL:
status = BDLIOCTL_GetControl(pBDLExtension, cbIn, cbOut, pIOBuffer, &cbOutUsed); break;
case BDD_IOCTL_SETCONTROL:
status = BDLIOCTL_SetControl(pBDLExtension, cbIn, cbOut, pIOBuffer, &cbOutUsed); break;
case BDD_IOCTL_CREATEHANDLEFROMDATA:
status = BDLIOCTL_CreateHandleFromData(pBDLExtension, cbIn, cbOut, pIOBuffer, &cbOutUsed); break;
case BDD_IOCTL_CLOSEHANDLE:
status = BDLIOCTL_CloseHandle(pBDLExtension, cbIn, cbOut, pIOBuffer, &cbOutUsed); break;
case BDD_IOCTL_GETDATAFROMHANDLE:
status = BDLIOCTL_GetDataFromHandle(pBDLExtension, cbIn, cbOut, pIOBuffer, &cbOutUsed); break;
case BDD_IOCTL_REGISTERNOTIFY:
status = BDLIOCTL_RegisterNotify(pBDLExtension, cbIn, cbOut, pIOBuffer, &cbOutUsed); break;
case BDD_IOCTL_GETNOTIFICATION:
status = BDLIOCTL_GetNotification(pBDLExtension, cbIn, cbOut, pIOBuffer, pIrp, &cbOutUsed); break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break; } Return:
//
// If the IRP isn't pending, then complete it
//
if (status != STATUS_PENDING) { pIrp->IoStatus.Information = cbOutUsed; pIrp->IoStatus.Status = status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); } KeAcquireSpinLock(&(pBDLExtension->SpinLock), &irql); pBDLExtension->IoCount--; KeReleaseSpinLock(&(pBDLExtension->SpinLock), irql);
IoReleaseRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) 'tCoI');
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLDeviceControl: Leave\n", __DATE__, __TIME__))
return (status); }
//
// BDLSystemControl()
//
//
//
NTSTATUS BDLSystemControl ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS; PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension = pDeviceObject->DeviceExtension;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLSystemControl: Enter\n", __DATE__, __TIME__))
//
// Becuase we are not a WMI provider all we have to do is pass this IRP down
//
IoSkipCurrentIrpStackLocation(pIrp); status = IoCallDriver(pBDLExtension->BdlExtenstion.pAttachedDeviceObject, pIrp);
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLSystemControl: Leave\n", __DATE__, __TIME__))
return (status); }
//
// BDLAddDevice()
//
// This routine creates an object for the physical device specified and
// sets up the deviceExtension.
//
NTSTATUS BDLAddDevice ( IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT pPhysicalDeviceObject ) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_OBJECT pDeviceObject = NULL; PBDL_DRIVER_EXTENSION pDriverExtension = NULL; PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension = NULL; BDSI_ADDDEVICE bdsiAddDeviceParams; ULONG i;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLAddDevice: Enter\n", __DATE__, __TIME__))
PAGED_CODE();
//
// Get the driver extension
//
pDriverExtension = IoGetDriverObjectExtension(pDriverObject, BDL_DRIVER_EXTENSION_ID); ASSERT(pDriverExtension != NULL);
//
// Create the device object
//
status = IoCreateDevice( pDriverObject, sizeof(BDL_INTERNAL_DEVICE_EXTENSION), NULL, FILE_DEVICE_BIOMETRIC, 0, TRUE, &pDeviceObject);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLAddDevice: IoCreateDevice failed with %lx\n", __DATE__, __TIME__, status))
goto ErrorReturn; }
pBDLExtension = pDeviceObject->DeviceExtension; RtlZeroMemory(pBDLExtension, sizeof(BDL_INTERNAL_DEVICE_EXTENSION));
//
// Attach the device to the stack
//
pBDLExtension->BdlExtenstion.Size = sizeof(BDL_DEVICEEXT); pBDLExtension->BdlExtenstion.pAttachedDeviceObject = IoAttachDeviceToDeviceStack( pDeviceObject, pPhysicalDeviceObject);
if (pBDLExtension->BdlExtenstion.pAttachedDeviceObject == NULL) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLAddDevice: IoAttachDeviceToDeviceStack failed with %lx\n", __DATE__, __TIME__, status))
status = STATUS_UNSUCCESSFUL; goto ErrorReturn; }
status = IoRegisterDeviceInterface( pPhysicalDeviceObject, &BiometricDeviceGuid, NULL, &(pBDLExtension->SymbolicLinkName)); ASSERT(status == STATUS_SUCCESS);
//
// Initialize the rest of the BDL device extension members in order
//
pBDLExtension->pDriverExtension = pDriverExtension;
KeInitializeSpinLock(&(pBDLExtension->SpinLock));
KeInitializeEvent(&(pBDLExtension->DeviceStartedEvent), NotificationEvent, FALSE);
pBDLExtension->IoCount = 0;
IoInitializeRemoveLock(&(pBDLExtension->RemoveLock), BDL_ULONG_TAG, 0, 20);
pBDLExtension->DeviceOpen = FALSE;
status = BDLGetDeviceCapabilities(pPhysicalDeviceObject, pBDLExtension); if (status != STATUS_SUCCESS) { goto ErrorReturn; }
KeInitializeSpinLock(&(pBDLExtension->ControlChangeStruct.ISRControlChangeLock));
KeInitializeDpc( &(pBDLExtension->ControlChangeStruct.DpcObject), BDLControlChangeDpc, pBDLExtension);
InitializeListHead(&(pBDLExtension->ControlChangeStruct.ISRControlChangeQueue));
for (i = 0; i < CONTROL_CHANGE_POOL_SIZE; i++) { pBDLExtension->ControlChangeStruct.rgControlChangePool[i].fUsed = FALSE; } KeQueryTickCount(&(pBDLExtension->ControlChangeStruct.StartTime)); pBDLExtension->ControlChangeStruct.NumCalls = 0; KeInitializeSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock)); InitializeListHead(&(pBDLExtension->ControlChangeStruct.IOCTLControlChangeQueue)); pBDLExtension->ControlChangeStruct.pIrp = NULL; InitializeListHead(&(pBDLExtension->ControlChangeStruct.ControlChangeRegistrationList)); pBDLExtension->CurrentPowerState = On;
pBDLExtension->fStartSucceeded = FALSE;
pBDLExtension->fDeviceRemoved = FALSE;
KeInitializeSpinLock(&(pBDLExtension->HandleListLock)); BDLInitializeHandleList(&(pBDLExtension->HandleList));
//
// finally, call the BDD's bdsiAddDevice
//
RtlZeroMemory(&bdsiAddDeviceParams, sizeof(bdsiAddDeviceParams)); bdsiAddDeviceParams.Size = sizeof(bdsiAddDeviceParams); bdsiAddDeviceParams.pPhysicalDeviceObject = pPhysicalDeviceObject; bdsiAddDeviceParams.pvBDDExtension = NULL;
status = pDriverExtension->bdsiFunctions.pfbdsiAddDevice( &(pBDLExtension->BdlExtenstion), &bdsiAddDeviceParams);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLAddDevice: bdsiAddDevice failed with %lx\n", __DATE__, __TIME__, status))
status = STATUS_UNSUCCESSFUL; goto ErrorReturn; }
pBDLExtension->BdlExtenstion.pvBDDExtension = bdsiAddDeviceParams.pvBDDExtension;
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLAddDevice: Leave\n", __DATE__, __TIME__))
return (status);
ErrorReturn:
if (pBDLExtension != NULL) { BDLCleanupDeviceCapabilities(pBDLExtension);
if (pBDLExtension->BdlExtenstion.pAttachedDeviceObject) { IoDetachDevice(pBDLExtension->BdlExtenstion.pAttachedDeviceObject); }
if (pBDLExtension->SymbolicLinkName.Buffer != NULL) { RtlFreeUnicodeString(&(pBDLExtension->SymbolicLinkName)); } }
if (pDeviceObject != NULL) { IoDeleteDevice(pDeviceObject); }
goto Return; }
//
// BDLPnP()
//
// This routine is called for all PnP notifications
//
NTSTATUS BDLPnP ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS; PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension = pDeviceObject->DeviceExtension; PIO_STACK_LOCATION pStackLocation = NULL; PDEVICE_OBJECT pAttachedDeviceObject = NULL; BOOLEAN fCompleteIrp = TRUE;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnP: Enter\n", __DATE__, __TIME__))
pAttachedDeviceObject = pBDLExtension->BdlExtenstion.pAttachedDeviceObject; pStackLocation = IoGetCurrentIrpStackLocation(pIrp);
//
// Acquire the remove lock with the 'Pnp ' tag if this is any IRP other
// than IRP_MN_REMOVE_DEVICE. If it is IRP_MN_REMOVE_DEVICE then acquire
// the lock with the 'Rmv ' tag
//
status = IoAcquireRemoveLock( &(pBDLExtension->RemoveLock), (pStackLocation->MinorFunction != IRP_MN_REMOVE_DEVICE) ? (PVOID) ' PnP' : (PVOID) ' vmR');
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPnP: IRP_MN_...%lx - Device Removed!!\n", __DATE__, __TIME__, pStackLocation->MinorFunction))
pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_DEVICE_REMOVED; IoCompleteRequest(pIrp, IO_NO_INCREMENT);
status = STATUS_DEVICE_REMOVED; goto Return; }
switch (pStackLocation->MinorFunction) { case IRP_MN_START_DEVICE:
status = BDLPnPStart( pBDLExtension, pAttachedDeviceObject, pIrp, pStackLocation); break;
case IRP_MN_QUERY_STOP_DEVICE:
status = BDLPnPQueryStop( pBDLExtension, pAttachedDeviceObject, pIrp);
break;
case IRP_MN_CANCEL_STOP_DEVICE:
status = BDLPnPCancelStop( pBDLExtension, pAttachedDeviceObject, pIrp);
break;
case IRP_MN_STOP_DEVICE:
status = BDLPnPStop( pBDLExtension, pAttachedDeviceObject, pIrp);
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
status = BDLPnPQueryRemove( pBDLExtension, pAttachedDeviceObject, pIrp);
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
status = BDLPnPCancelRemove( pBDLExtension, pAttachedDeviceObject, pIrp);
break;
case IRP_MN_REMOVE_DEVICE:
status = BDLPnPRemove( pBDLExtension, pDeviceObject, pAttachedDeviceObject, pIrp);
fCompleteIrp = FALSE;
break;
case IRP_MN_SURPRISE_REMOVAL:
status = BDLPnPSurpriseRemoval( pBDLExtension, pAttachedDeviceObject, pIrp);
fCompleteIrp = FALSE;
break;
default: //
// This is an Irp that is only useful for underlying drivers
//
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnP: IRP_MN_...%lx\n", __DATE__, __TIME__, pStackLocation->MinorFunction))
IoSkipCurrentIrpStackLocation(pIrp); status = IoCallDriver(pAttachedDeviceObject, pIrp); fCompleteIrp = FALSE;
break; }
//
// If we actually processed the IRP and didn't skip it then complete it
//
if (fCompleteIrp == TRUE) { pIrp->IoStatus.Status = status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); }
//
// The BDLPnPRemove() function itself will release the remove lock since it
// has to wait on all the other holders of the lock defore deleting the device
// object. So we don't call IoReleaseRemoveLock() here if this is a
// IRP_MN_REMOVE_DEVICE IRP
//
if (pStackLocation->MinorFunction != IRP_MN_REMOVE_DEVICE) { IoReleaseRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) ' PnP'); }
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnP: Leave\n", __DATE__, __TIME__))
return (status); }
//
// BDLPower()
//
// This routine is called for all Power notifications
//
NTSTATUS BDLPower ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS; PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension = pDeviceObject->DeviceExtension; PIO_STACK_LOCATION pStackLocation = NULL; PDEVICE_OBJECT pAttachedDeviceObject = NULL; BOOLEAN fCompleteIrp = TRUE; IRP_ACTION IRPAction = SkipRequest; PIO_COMPLETION_ROUTINE IoCompletionRoutine = NULL; POWER_IRP_CONTEXT *pPowerIrpContext = NULL; BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPower: Enter\n", __DATE__, __TIME__))
pAttachedDeviceObject = pBDLExtension->BdlExtenstion.pAttachedDeviceObject; pStackLocation = IoGetCurrentIrpStackLocation(pIrp);
//
// Acquire the remove lock
//
status = IoAcquireRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) 'rwoP');
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPower: IRP_MN_...%lx - Device Removed!!\n", __DATE__, __TIME__, pStackLocation->MinorFunction))
PoStartNextPowerIrp(pIrp); pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_DEVICE_REMOVED; IoCompleteRequest(pIrp, IO_NO_INCREMENT);
status = STATUS_DEVICE_REMOVED; goto Return; }
switch (pStackLocation->Parameters.Power.Type) { case DevicePowerState: switch (pStackLocation->MinorFunction) { case IRP_MN_QUERY_POWER:
status = BDLDeviceQueryPower( pBDLExtension, pStackLocation, &IRPAction, &IoCompletionRoutine);
break;
case IRP_MN_SET_POWER:
status = BDLDeviceSetPower( pDeviceObject, pBDLExtension, pStackLocation, &IRPAction, &IoCompletionRoutine);
break;
default:
ASSERT(FALSE); break;
} // switch (pStackLocation->MinorFunction)
break;
case SystemPowerState: switch (pStackLocation->MinorFunction) { case IRP_MN_QUERY_POWER: status = BDLSystemQueryPower( pBDLExtension, pStackLocation, &IRPAction, &IoCompletionRoutine);
break;
case IRP_MN_SET_POWER: status = BDLSystemSetPower( pBDLExtension, pStackLocation, &IRPAction, &IoCompletionRoutine);
break;
default: ASSERT(FALSE); break;
} // switch (pStackLocation->MinorFunction)
break;
default:
ASSERT(FALSE); break;
} // switch (pStackLocation->Parameters.Power.Type)
switch (IRPAction) { case SkipRequest:
IoReleaseRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) 'rwoP');
PoStartNextPowerIrp(pIrp); IoSkipCurrentIrpStackLocation(pIrp); status = PoCallDriver(pAttachedDeviceObject, pIrp);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPower: PoCallDriver failed with %lx\n", __DATE__, __TIME__, status))
goto ErrorReturn; }
break;
case CompleteRequest:
pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0;
IoReleaseRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) 'rwoP');
PoStartNextPowerIrp(pIrp); IoCompleteRequest(pIrp, IO_NO_INCREMENT);
break;
case MarkPending:
//
// Allocate the context struct that all the IRPs use
//
pPowerIrpContext = ExAllocatePoolWithTag( PagedPool, sizeof(POWER_IRP_CONTEXT), BDL_ULONG_TAG);
if (pPowerIrpContext == NULL) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPower: ExAllocatePoolWithTag failed\n", __DATE__, __TIME__))
status = STATUS_NO_MEMORY; goto ErrorReturn; }
//
// Fill in the context struct
//
pPowerIrpContext->pBDLExtension = pBDLExtension; pPowerIrpContext->pIrp = pIrp; //
// Mark the irp as pending and setup the completion routine, then call the driver
//
IoMarkIrpPending(pIrp); IoCopyCurrentIrpStackLocationToNext(pIrp); IoSetCompletionRoutine(pIrp, IoCompletionRoutine, pPowerIrpContext, TRUE, TRUE, TRUE); status = PoCallDriver(pDeviceObject, pIrp); ASSERT(status == STATUS_PENDING);
if (status != STATUS_PENDING) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPower: PoCallDriver should have returned STATUS_PENDING but returned %lx\n", __DATE__, __TIME__, status))
// FIX FIX
//
// I have no idea what can be done to recover in this case
//
}
break; } // switch (IRPAction)
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPower: Leave\n", __DATE__, __TIME__))
return (status);
ErrorReturn:
pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0;
IoReleaseRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) 'rwoP');
PoStartNextPowerIrp(pIrp); IoCompleteRequest(pIrp, IO_NO_INCREMENT);
goto Return; }
/////////////////////////////////////////////////////////////////////////////////////////
//
// These functions are all the handlers for Power events or supporting IoCompletion
// routines for the handlers
//
VOID BDLSystemPowerCompleted ( IN PDEVICE_OBJECT pDeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK pIoStatus ) { POWER_IRP_CONTEXT *pPowerIrpContext = (POWER_IRP_CONTEXT *) Context; PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension = pPowerIrpContext->pBDLExtension; PIRP pIrp = pPowerIrpContext->pIrp;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLSystemQueryPowerCompleted: Enter\n", __DATE__, __TIME__))
//
// Set the status of the System Power IRP to be the return status of the
// Device Power IRP that was initiated by calling PoRequestPowerIrp() in
// BDLSystemPowerIoCompletion()
//
pIrp->IoStatus.Status = pIoStatus->Status; pIrp->IoStatus.Information = 0;
IoReleaseRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) 'rwoP');
PoStartNextPowerIrp(pIrp); IoCompleteRequest(pIrp, IO_NO_INCREMENT);
ExFreePoolWithTag(pPowerIrpContext, BDL_ULONG_TAG);
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLSystemQueryPowerCompleted: Leave\n", __DATE__, __TIME__)) }
NTSTATUS BDLSystemPowerIoCompletion ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID Context ) { NTSTATUS status = STATUS_SUCCESS; POWER_IRP_CONTEXT *pPowerIrpContext = (POWER_IRP_CONTEXT *) Context; PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension = pPowerIrpContext->pBDLExtension; PIO_STACK_LOCATION pStackLocation = IoGetCurrentIrpStackLocation(pIrp); POWER_STATE PowerState;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLSystemQueryPowerIoCompletion: Enter\n", __DATE__, __TIME__))
//
// If a lower level driver failed the request then just complete the IRP
// and return the status set by the lower level driver
//
if (pIrp->IoStatus.Status != STATUS_SUCCESS) { status = pIrp->IoStatus.Status; BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLSystemQueryPowerIoCompletion: PoRequestPowerIrp did not return STATUS_PENDING, but returned %lx\n", __DATE__, __TIME__, status))
goto ErrorReturn; }
//
// Figure out what device power state to request
//
switch (pStackLocation->Parameters.Power.State.SystemState) { case PowerSystemMaximum: case PowerSystemWorking: PowerState.DeviceState = PowerDeviceD0;
break;
case PowerSystemSleeping1: case PowerSystemSleeping2: case PowerSystemSleeping3:
// FIX FIX
//
// For now, just fall through and map these system states to the
// PowerDeviceD3 device state. Ultimately, these system states should
// map to the PowerDeviceD2 device state
//
case PowerSystemHibernate: case PowerSystemShutdown:
PowerState.DeviceState = PowerDeviceD3;
break;
default:
ASSERT(FALSE); }
//
// Send a query power IRP to the device and pass in a completion routine
// which will check to see if the device query power IRP was completed
// successfully or not and will then complete the system query IRP
//
status = PoRequestPowerIrp ( pDeviceObject, pStackLocation->MinorFunction, PowerState, BDLSystemPowerCompleted, pPowerIrpContext, NULL); if (status == STATUS_PENDING) { status = STATUS_MORE_PROCESSING_REQUIRED; } else {
pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0;
BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLSystemQueryPowerIoCompletion: PoRequestPowerIrp did not return STATUS_PENDING, but returned %lx\n", __DATE__, __TIME__, status))
goto ErrorReturn; }
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLSystemQueryPowerIoCompletion: Leave\n", __DATE__, __TIME__))
return (status);
ErrorReturn:
//
// The IRP isn't going to be completed in the device query IRP completion routine,
// so we need to complete it here
//
IoReleaseRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) 'rwoP'); PoStartNextPowerIrp(pIrp); IoCompleteRequest(pIrp, IO_NO_INCREMENT);
ExFreePoolWithTag(pPowerIrpContext, BDL_ULONG_TAG); goto Return; }
NTSTATUS BDLSystemQueryPower ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PIO_STACK_LOCATION pStackLocation, OUT IRP_ACTION *pIRPAction, OUT PIO_COMPLETION_ROUTINE *pIoCompletionRoutine ) { NTSTATUS status = STATUS_SUCCESS; KIRQL irql;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPowerSystemQuery: Enter\n", __DATE__, __TIME__))
//
// Set these output variables here just in case we mark as pending.
//
*pIoCompletionRoutine = BDLSystemPowerIoCompletion;
switch (pStackLocation->Parameters.Power.State.SystemState) { case PowerSystemMaximum: case PowerSystemWorking: //
// Because we are transitioning into a working state we don't
// need to check anything... since we can definitely make the
// transition. Mark as pending and continue processing in
// completion routine.
//
*pIRPAction = MarkPending; break;
case PowerSystemSleeping1: case PowerSystemSleeping2: case PowerSystemSleeping3: case PowerSystemHibernate: case PowerSystemShutdown:
//
// Since we are going into a low power mode or being shutdown
// check to see if there are any outstanding IO calls
//
KeAcquireSpinLock(&(pBDLExtension->SpinLock), &irql); if (pBDLExtension->IoCount == 0) { //
// Block any further IOCTLs
//
KeClearEvent(&(pBDLExtension->DeviceStartedEvent));
//
// Mark as pending and continue processing in completion routine.
//
*pIRPAction = MarkPending; } else { //
// We can't go into sleep mode because the device is busy
//
status = STATUS_DEVICE_BUSY; *pIRPAction = CompleteRequest; } KeReleaseSpinLock(&(pBDLExtension->SpinLock), irql);
break;
case PowerSystemUnspecified:
ASSERT(FALSE);
status = STATUS_UNSUCCESSFUL; *pIRPAction = CompleteRequest; }
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPowerSystemQuery: Leave\n", __DATE__, __TIME__)) return (status); }
NTSTATUS BDLSystemSetPower ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PIO_STACK_LOCATION pStackLocation, OUT IRP_ACTION *pIRPAction, OUT PIO_COMPLETION_ROUTINE *pIoCompletionRoutine ) { NTSTATUS status = STATUS_SUCCESS; KIRQL irql;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLSystemSetPower: Enter\n", __DATE__, __TIME__))
//
// Set the completion routing here just in case we mark as pending.
//
*pIoCompletionRoutine = BDLSystemPowerIoCompletion;
switch (pStackLocation->Parameters.Power.State.SystemState) { case PowerSystemMaximum: case PowerSystemWorking: //
// If we are already in the requested state then skip the request,
// otherwise mark as pending which will pass the IRP down and continue
// processing in the completion routine
//
if (pBDLExtension->CurrentPowerState == On) { *pIRPAction = SkipRequest; } else { *pIRPAction = MarkPending; } break;
case PowerSystemSleeping1: case PowerSystemSleeping2: case PowerSystemSleeping3:
// FIX FIX
//
// for now just fall through on these
//
case PowerSystemHibernate: case PowerSystemShutdown:
//
// If we are already in the requested state then skip the request,
// otherwise mark as pending which will pass the IRP down and continue
// processing in the completion routine
//
if (pBDLExtension->CurrentPowerState == Off) { *pIRPAction = SkipRequest; } else { *pIRPAction = MarkPending; }
break;
case PowerSystemUnspecified:
ASSERT(FALSE);
status = STATUS_UNSUCCESSFUL; *pIRPAction = CompleteRequest; }
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLSystemSetPower: Leave\n", __DATE__, __TIME__)) return (status);
}
NTSTATUS BDLDevicePowerIoCompletion ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID Context ) { NTSTATUS status = STATUS_SUCCESS; POWER_IRP_CONTEXT *pPowerIrpContext = (POWER_IRP_CONTEXT *) Context; PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension = pPowerIrpContext->pBDLExtension; PIO_STACK_LOCATION pStackLocation = IoGetCurrentIrpStackLocation(pIrp); PBDL_DRIVER_EXTENSION pDriverExtension = pBDLExtension->pDriverExtension; BDSI_SETPOWERSTATE bdsiSetPowerStateParams; BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLDevicePowerIoCompletion: Enter\n", __DATE__, __TIME__))
//
// If this is a completion call for an IRP_MN_SET_POWER IRP, AND it is going
// into a working state, then call the BDD, otherwise just complete the IRP
// since it is one of the following:
// 1) a completion for an IRP_MN_SET_POWER IRP that is going into low power/shutdown
// (in which case the BDD was already called)
// 2) a completion for an IRP_MN_QUERY_POWER IRP
//
if ((pStackLocation->MinorFunction == IRP_MN_SET_POWER) && ( (pStackLocation->Parameters.Power.State.DeviceState == PowerDeviceD0) || (pStackLocation->Parameters.Power.State.DeviceState == PowerDeviceMaximum))) { RtlZeroMemory(&bdsiSetPowerStateParams, sizeof(bdsiSetPowerStateParams)); bdsiSetPowerStateParams.Size = sizeof(bdsiSetPowerStateParams); bdsiSetPowerStateParams.PowerState = On; status = pDriverExtension->bdsiFunctions.pfbdsiSetPowerState( &(pBDLExtension->BdlExtenstion), &bdsiSetPowerStateParams);
if (status == STATUS_SUCCESS) { PoSetPowerState( pDeviceObject, DevicePowerState, pStackLocation->Parameters.Power.State); } else { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLDevicePowerIoCompletion: pfbdsiSetPowerState failed with %lx\n", __DATE__, __TIME__, status)) }
pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; } else { status = pIrp->IoStatus.Status; }
IoReleaseRemoveLock(&(pBDLExtension->RemoveLock), (PVOID) 'rwoP');
PoStartNextPowerIrp(pIrp); IoCompleteRequest(pIrp, IO_NO_INCREMENT);
ExFreePoolWithTag(pPowerIrpContext, BDL_ULONG_TAG);
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLDevicePowerIoCompletion: Leave\n", __DATE__, __TIME__))
return (status); }
NTSTATUS BDLDeviceQueryPower ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PIO_STACK_LOCATION pStackLocation, OUT IRP_ACTION *pIRPAction, OUT PIO_COMPLETION_ROUTINE *pIoCompletionRoutine ) { NTSTATUS status = STATUS_SUCCESS; KIRQL irql; BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLDeviceQueryPower: Enter\n", __DATE__, __TIME__))
//
// Set the completion routine here just in case we mark as pending.
//
*pIoCompletionRoutine = BDLDevicePowerIoCompletion;
switch (pStackLocation->Parameters.Power.State.DeviceState) { case PowerDeviceD0: case PowerDeviceMaximum:
//
// Because we are transitioning into a working state we don't
// need to check anything... since we can definitely make the
// transition. Mark as pending and continue processing in
// completion routine.
//
*pIRPAction = MarkPending;
break;
case PowerDeviceD2: case PowerDeviceD3:
break;
//
// Since we are going into a low power mode or being shutdown
// check to see if there are any outstanding IO calls
//
KeAcquireSpinLock(&(pBDLExtension->SpinLock), &irql); if (pBDLExtension->IoCount == 0) { //
// Block any further IOCTLs
//
KeClearEvent(&(pBDLExtension->DeviceStartedEvent));
//
// Mark as pending and continue processing in completion routine.
//
*pIRPAction = MarkPending; } else { //
// We can't go into sleep mode because the device is busy
//
status = STATUS_DEVICE_BUSY; *pIRPAction = CompleteRequest; } KeReleaseSpinLock(&(pBDLExtension->SpinLock), irql);
case PowerDeviceD1: case PowerDeviceUnspecified:
//
// These states are unsupported
//
ASSERT(FALSE);
status = STATUS_UNSUCCESSFUL; *pIRPAction = CompleteRequest;
break; }
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLDeviceQueryPower: Leave\n", __DATE__, __TIME__)) return (status); }
NTSTATUS BDLDeviceSetPower ( IN PDEVICE_OBJECT pDeviceObject, IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PIO_STACK_LOCATION pStackLocation, OUT IRP_ACTION *pIRPAction, OUT PIO_COMPLETION_ROUTINE *pIoCompletionRoutine ) { NTSTATUS status = STATUS_SUCCESS; PBDL_DRIVER_EXTENSION pDriverExtension = pBDLExtension->pDriverExtension; BDSI_SETPOWERSTATE bdsiSetPowerStateParams; BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLDeviceSetPower: Enter\n", __DATE__, __TIME__))
//
// Set the completion routine here just in case we mark as pending.
//
*pIoCompletionRoutine = BDLDevicePowerIoCompletion;
switch (pStackLocation->Parameters.Power.State.DeviceState) { case PowerDeviceD0: case PowerDeviceMaximum:
//
// If we are already in the requested state then skip the request,
// otherwise mark as pending which will pass the IRP down and continue
// processing in the completion routine
//
if (pBDLExtension->CurrentPowerState == On) { *pIRPAction = SkipRequest; } else { *pIRPAction = MarkPending; }
break; case PowerDeviceD2: case PowerDeviceD3:
//
// If we are already in the requested state then skip the request,
// otherwise call the BDD and tell it to power down, then mark as
// pending which will pass the IRP down and then complete the IRP
// in the completion routine
//
if (pBDLExtension->CurrentPowerState == Off) { *pIRPAction = SkipRequest; } else { RtlZeroMemory(&bdsiSetPowerStateParams, sizeof(bdsiSetPowerStateParams)); bdsiSetPowerStateParams.Size = sizeof(bdsiSetPowerStateParams); bdsiSetPowerStateParams.PowerState = Off; status = pDriverExtension->bdsiFunctions.pfbdsiSetPowerState( &(pBDLExtension->BdlExtenstion), &bdsiSetPowerStateParams); if (status == STATUS_SUCCESS) { PoSetPowerState( pDeviceObject, DevicePowerState, pStackLocation->Parameters.Power.State);
*pIRPAction = MarkPending; } else { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLDeviceSetPower: pfbdsiSetPowerState failed with %lx\n", __DATE__, __TIME__, status))
*pIRPAction = CompleteRequest; } }
break;
case PowerDeviceD1: case PowerDeviceUnspecified:
//
// These states are unsupported
//
ASSERT(FALSE);
status = STATUS_UNSUCCESSFUL; *pIRPAction = CompleteRequest;
break; }
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLDeviceSetPower: Leave\n", __DATE__, __TIME__)) return (status);
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// These functions are all the handlers for PNP events
//
NTSTATUS BDLPnPStart ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp, PIO_STACK_LOCATION pStackLocation ) { NTSTATUS status = STATUS_SUCCESS; PBDL_DRIVER_EXTENSION pDriverExtension = pBDLExtension->pDriverExtension; BDSI_INITIALIZERESOURCES bdsiInitializeResourcesParams;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPStartDevice: Enter\n", __DATE__, __TIME__))
//
// We have to call the lower level driver first when starting up
//
status = BDLCallLowerLevelDriverAndWait(pAttachedDeviceObject, pIrp);
if (!NT_SUCCESS(status)) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPnPStartDevice: BDLCallLowerLevelDriverAndWait failed with %lx\n", __DATE__, __TIME__, status))
goto Return; }
//
// Call the BDD's InitializeResources function
//
RtlZeroMemory(&bdsiInitializeResourcesParams, sizeof(bdsiInitializeResourcesParams)); bdsiInitializeResourcesParams.Size = sizeof(bdsiInitializeResourcesParams); bdsiInitializeResourcesParams.pAllocatedResources = pStackLocation->Parameters.StartDevice.AllocatedResources; bdsiInitializeResourcesParams.pAllocatedResourcesTranslated = pStackLocation->Parameters.StartDevice.AllocatedResourcesTranslated;
status = pDriverExtension->bdsiFunctions.pfbdsiInitializeResources( &(pBDLExtension->BdlExtenstion), &bdsiInitializeResourcesParams);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPnPStartDevice: pfbdsiInitializeResources failed with %lx\n", __DATE__, __TIME__, status))
goto Return; }
//
// Save the device info
//
RtlCopyMemory( &(pBDLExtension->wszSerialNumber[0]), &(bdsiInitializeResourcesParams.wszSerialNumber[0]), sizeof(pBDLExtension->wszSerialNumber)); pBDLExtension->HWVersionMajor = bdsiInitializeResourcesParams.HWVersionMajor; pBDLExtension->HWVersionMinor = bdsiInitializeResourcesParams.HWVersionMinor; pBDLExtension->HWBuildNumber = bdsiInitializeResourcesParams.HWBuildNumber; pBDLExtension->BDDVersionMajor = bdsiInitializeResourcesParams.BDDVersionMajor; pBDLExtension->BDDVersionMinor = bdsiInitializeResourcesParams.BDDVersionMinor; pBDLExtension->BDDBuildNumber = bdsiInitializeResourcesParams.BDDBuildNumber;
//
// Enable the device interface
//
status = IoSetDeviceInterfaceState(&(pBDLExtension->SymbolicLinkName), TRUE); if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPnPStartDevice: IoSetDeviceInterfaceState failed with %lx\n", __DATE__, __TIME__, status))
pDriverExtension->bdsiFunctions.pfbdsiReleaseResources(&(pBDLExtension->BdlExtenstion));
goto Return; }
//
// This is set here indicating that BDLPnPRemove() should clean up whatever was
// inizialized during BDLPnPStart(). If this is not set then BDLPnPRemove()
// should only cleanup what BDLAddDevice() initialized.
//
pBDLExtension->fStartSucceeded = TRUE;
//
// We are open for business so set the device to started
//
KeSetEvent(&(pBDLExtension->DeviceStartedEvent), 0, FALSE);
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPStartDevice: Leave\n", __DATE__, __TIME__))
return (status); }
NTSTATUS BDLPnPQueryStop ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS; KIRQL irql;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPQueryStop: Enter\n", __DATE__, __TIME__))
KeAcquireSpinLock(&(pBDLExtension->SpinLock), &irql); //
// Check the IO count to see if we are currently doing anything
//
if (pBDLExtension->IoCount > 0) { //
// We refuse to stop if we have pending IO
//
KeReleaseSpinLock(&(pBDLExtension->SpinLock), irql); status = STATUS_DEVICE_BUSY; } else { //
// Stop processing IO requests by clearing the device started event
//
KeClearEvent(&(pBDLExtension->DeviceStartedEvent));
KeReleaseSpinLock(&(pBDLExtension->SpinLock), irql);
//
// Send to the lower level driver
//
status = BDLCallLowerLevelDriverAndWait(pAttachedDeviceObject, pIrp); }
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPQueryStop: Leave\n", __DATE__, __TIME__)) return (status); }
NTSTATUS BDLPnPCancelStop ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS; BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPCancelStop: Enter\n", __DATE__, __TIME__)) //
// Send to the lower level driver
//
status = BDLCallLowerLevelDriverAndWait(pAttachedDeviceObject, pIrp);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPnPCancelStop: BDLCallLowerLevelDriverAndWait failed with %lx\n", __DATE__, __TIME__, status))
goto Return; }
//
// Set the device to started
//
KeSetEvent(&(pBDLExtension->DeviceStartedEvent), 0, FALSE);
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPCancelStop: Leave\n", __DATE__, __TIME__)) return (status); }
NTSTATUS BDLPnPStop ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS; PBDL_DRIVER_EXTENSION pDriverExtension = pBDLExtension->pDriverExtension;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPStop: Enter\n", __DATE__, __TIME__))
//
// Disable the device interface (and ignore possible errors)
//
IoSetDeviceInterfaceState(&(pBDLExtension->SymbolicLinkName), FALSE);
//
// Call the BDD's ReleaseResources
//
status = pDriverExtension->bdsiFunctions.pfbdsiReleaseResources(&(pBDLExtension->BdlExtenstion));
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPnPStop: pfbdsiReleaseResources failed with %lx\n", __DATE__, __TIME__, status))
goto Return; }
//
// Set this here indicating the whatever was initialized during BDLPnPStart() has
// now been cleaned up.
//
pBDLExtension->fStartSucceeded = FALSE; //
// Send to the lower level driver
//
status = BDLCallLowerLevelDriverAndWait(pAttachedDeviceObject, pIrp);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPnPStop: BDLCallLowerLevelDriverAndWait failed with %lx\n", __DATE__, __TIME__, status))
goto Return; }
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPStop: Leave\n", __DATE__, __TIME__)) return (status); }
NTSTATUS BDLPnPQueryRemove ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPQueryRemove: Enter\n", __DATE__, __TIME__))
//
// Disable the interface (and ignore possible errors)
//
IoSetDeviceInterfaceState(&(pBDLExtension->SymbolicLinkName), FALSE);
//
// If someone is connected to us then fail the call. We will enable
// the device interface in IRP_MN_CANCEL_REMOVE_DEVICE again
//
if (pBDLExtension->DeviceOpen) { status = STATUS_UNSUCCESSFUL; goto Return; }
//
// Send to the lower level driver
//
status = BDLCallLowerLevelDriverAndWait(pAttachedDeviceObject, pIrp);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPnPQueryRemove: BDLCallLowerLevelDriverAndWait failed with %lx\n", __DATE__, __TIME__, status))
goto Return; }
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPQueryRemove: Leave\n", __DATE__, __TIME__)) return (status); }
NTSTATUS BDLPnPCancelRemove ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPCancelRemove: Enter\n", __DATE__, __TIME__))
//
// Send to the lower level driver first
//
status = BDLCallLowerLevelDriverAndWait(pAttachedDeviceObject, pIrp);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPnPCancelRemove: BDLCallLowerLevelDriverAndWait failed with %lx\n", __DATE__, __TIME__, status))
goto Return; }
//
// Enable the interface
//
status = IoSetDeviceInterfaceState(&(pBDLExtension->SymbolicLinkName), TRUE);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLPnPCancelRemove: IoSetDeviceInterfaceState failed with %lx\n", __DATE__, __TIME__, status))
goto Return; }
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPCancelRemove: Leave\n", __DATE__, __TIME__)) return (status); }
NTSTATUS BDLHandleRemove ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS; PBDL_DRIVER_EXTENSION pDriverExtension = pBDLExtension->pDriverExtension;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLHandleRemove: Enter\n", __DATE__, __TIME__)) //
// Set this event so that any outstanding IOCTLs will be released.
// It is anti-intuitive to set the started event when the device is
// removed, but once this event is set, and the IOCTL threads get
// released, they will all fail when they try to acquire the remove lock.
//
// This handles the situation when you have a stopped device, a blocked
// IOCTL call, and then the device is removed.
//
KeSetEvent(&(pBDLExtension->DeviceStartedEvent), 0, FALSE);
//
// Disable the interface
//
IoSetDeviceInterfaceState(&(pBDLExtension->SymbolicLinkName), FALSE);
//
// Clean up any outstanding notification info and data handles
//
BDLCleanupNotificationStruct(pBDLExtension); BDLCleanupDataHandles(pBDLExtension);
//
// If the device is currently started, then stop it.
//
if (pBDLExtension->fStartSucceeded == TRUE) { status = pDriverExtension->bdsiFunctions.pfbdsiReleaseResources(&(pBDLExtension->BdlExtenstion));
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLHandleRemove: pfbdsiReleaseResources failed with %lx\n", __DATE__, __TIME__, status)) }
pBDLExtension->fStartSucceeded = FALSE; }
//
// Tell the BDD to remove the device
//
status = pDriverExtension->bdsiFunctions.pfbdsiRemoveDevice(&(pBDLExtension->BdlExtenstion));
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLHandleRemove: pfbdsiRemoveDevice failed with %lx\n", __DATE__, __TIME__, status)) }
//
// Send to the lower level driver
//
IoSkipCurrentIrpStackLocation(pIrp); status = IoCallDriver(pAttachedDeviceObject, pIrp);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLHandleRemove: IoCallDriver failed with %lx\n", __DATE__, __TIME__, status)) }
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLHandleRemove: Leave\n", __DATE__, __TIME__))
return (status); }
NTSTATUS BDLPnPRemove ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pDeviceObject, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPRemove: Enter\n", __DATE__, __TIME__))
//
// If there was a surprise removal then we don't need to cleanup...
// since the surprise removal already did it
//
if (pBDLExtension->fDeviceRemoved == FALSE) { pBDLExtension->fDeviceRemoved = TRUE; BDLHandleRemove(pBDLExtension, pAttachedDeviceObject, pIrp); }
//
// Wait until there are no more outstanding IRPs
//
IoReleaseRemoveLockAndWait(&(pBDLExtension->RemoveLock), (PVOID) ' vmR');
//
// cleanup stuff that was initialized in AddDevice
//
BDLCleanupDeviceCapabilities(pBDLExtension); IoDetachDevice(pAttachedDeviceObject); RtlFreeUnicodeString(&(pBDLExtension->SymbolicLinkName));
IoDeleteDevice(pDeviceObject);
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPRemove: Leave\n", __DATE__, __TIME__))
return (status); }
NTSTATUS BDLPnPSurpriseRemoval ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN PDEVICE_OBJECT pAttachedDeviceObject, IN PIRP pIrp ) { NTSTATUS status = STATUS_SUCCESS;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPSurpriseRemoval: Enter\n", __DATE__, __TIME__))
pBDLExtension->fDeviceRemoved = TRUE;
//
// Don't need to check errors, nothing we can do.
//
BDLHandleRemove(pBDLExtension, pAttachedDeviceObject, pIrp); BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLPnPSurpriseRemoval: Leave\n", __DATE__, __TIME__)) return (status); }
/////////////////////////////////////////////////////////////////////////////////////////
//
// These functions are exported by the BDL
//
//
// bdliInitialize()
//
// Called in response to the BDD receiving its DriverEntry call. This lets the BDL
// know that a new BDD has been loaded and allows the BDL to initialize its state so that
// it can manage the newly loaded BDD.
//
// The bdliInitialize call will set the appropriate fields in the DRIVER_OBJECT so that
// the BDL will receive all the necessary callbacks from the system for PNP events,
// Power events, and general driver functionality. The BDL will then forward calls that
// require hardware support to the BDD that called bdliInitialize (it will do so using
// the BDDI and BDSI APIs). A BDD must call the bdliInitialize call during its
// DriverEntry function.
//
// PARAMETERS:
// DriverObject This must be the DRIVER_OBJECT pointer that was passed into the
// BDD's DriverEntry call.
// RegistryPath This must be the UNICODE_STRING pointer that was passed into the
// BDD's DriverEntry call.
// pBDDIFunctions Pointer to a BDLI_BDDIFUNCTIONS structure that is filled in with the
// entry points that the BDD exports to support the BDDI API set. The
// pointers themselves are copied by the BDL, as opposed to saving the
// pBDDIFunctions pointer, so the memory pointed to by pBDDIFunctions
// need not remain accessible after the bdliInitialize call.
// pBDSIFunctions Pointer to a BDLI_BDSIFUNCTIONS structure that is filled in with
// the entry points that the BDD exports to support the BDSI API set.
// The pointers themselves are copied by the BDL, as opposed to saving
// the pBDSIFunctions pointer, so the memory pointed to by
// pBDSIFunctions need not remain accessible after the bdliInitialize
// call.
// Flags Unused. Must be 0.
// pReserved Unused. Must be NULL.
//
// RETURNS:
// STATUS_SUCCESS If the bdliInitialize call succeeded
//
NTSTATUS bdliInitialize ( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegistryPath, IN PBDLI_BDDIFUNCTIONS pBDDIFunctions, IN PBDLI_BDSIFUNCTIONS pBDSIFunctions, IN ULONG Flags, IN PVOID pReserved ) { NTSTATUS status = STATUS_SUCCESS; PBDL_DRIVER_EXTENSION pDriverExtension = NULL;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!bdliInitialize: Enter\n", __DATE__, __TIME__))
//
// Initialize the Driver Object with the BDL's entry points
//
pDriverObject->DriverUnload = BDLDriverUnload; pDriverObject->MajorFunction[IRP_MJ_CREATE] = BDLCreate; pDriverObject->MajorFunction[IRP_MJ_CLOSE] = BDLClose; pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = BDLCleanup; pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = BDLDeviceControl; pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = BDLSystemControl; pDriverObject->MajorFunction[IRP_MJ_PNP] = BDLPnP; pDriverObject->MajorFunction[IRP_MJ_POWER] = BDLPower; pDriverObject->DriverExtension->AddDevice = BDLAddDevice;
//
// Allocate a slot for the BDL driver extension structure
//
status = IoAllocateDriverObjectExtension( pDriverObject, BDL_DRIVER_EXTENSION_ID, sizeof(BDL_DRIVER_EXTENSION), &pDriverExtension);
if (status != STATUS_SUCCESS) { //
// This could happen if the BDD stole our slot
//
if (status == STATUS_OBJECT_NAME_COLLISION ) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!bdliInitialize: The BDD stole our DriverExtension slot\n", __DATE__, __TIME__)) } else { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!bdliInitialize: IoAllocateDriverObjectExtension failed with %lx\n", __DATE__, __TIME__, status)) }
goto Return; }
//
// Initialize the driver extension structure
//
pDriverExtension->bddiFunctions = *pBDDIFunctions; pDriverExtension->bdsiFunctions = *pBDSIFunctions;
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!bdliInitialize: Leave\n", __DATE__, __TIME__))
return (status); }
//
// bdliAlloc()
//
// Allocates memory that can be returned to the BDL.
//
// The BDD must always use this function to allocate memory that it will return to the
// BDL as an OUT parameter of a BDDI call. Once memory has been returned to the BDL,
// it will be owned and managed exclusively by the BDL and must not be further referenced
// by the BDD. (Each BDDI call that requires the use of bdliAlloc will note it).
//
// PARAMETERS:
// pBDLExt Pointer to the BDL_DEVICEEXT structure that was passed into the
// bdsiAddDevice call.
// NumBytes The number of bytes to allocate.
// Flags Unused. Must be 0.
//
// RETURNS:
// Returns a pointer to the allocated memory, or NULL if the function fails.
//
void * bdliAlloc ( IN PBDL_DEVICEEXT pBDLExt, IN ULONG NumBytes, IN ULONG Flags ) { return (ExAllocatePoolWithTag(PagedPool, NumBytes, BDLI_ULONG_TAG)); }
//
// bdliFree()
//
// Frees memory allocated by bdliAlloc.
//
// Memory allocated by bdliAlloc is almost always passed to the BDL as a channel product
// (as a BLOCK-type item) and subsequently freed by the BDL. However, if an error
// occurs while processing a channel, the BDD may need to call bdliFree to free memory it
// previous allocated via bdliAlloc.
//
// PARAMETERS:
// pvBlock Block of memory passed in by the BDL.
//
// RETURNS:
// No return value.
//
void bdliFree ( IN PVOID pvBlock ) { ExFreePoolWithTag(pvBlock, BDLI_ULONG_TAG); }
//
// bdliLogError()
//
// Writes an error to the event log.
//
// Provides a simple mechanism for BDD writers to write errors to the system event log
// without the overhead of registering with the event logging subsystem.
//
// PARAMETERS:
// pObject If the error being logged is device specific then this must be a
// pointer to the BDL_DEVICEEXT structure that was passed into the
// bdsiAddDevice call when the device was added. If the error being
// logged is a general BDD error, then this must be same DRIVER_OBJECT
// structure pointer that was passed into the DriverEntry call of the
// BDD when the driver was loaded.
// ErrorCode Error code of the function logging the error.
// Insertion An insertion string to be written to the event log. Your message file
// must have a place holder for the insertion. For example, "serial port
// %2 is either not available or used by another device". In this
// example, %2 will be replaced by the insertion string. Note that %1 is
// reserved for the file name.
// cDumpData The number of bytes pointed to by pbDumpData.
// pDumpData A data block to be displayed in the data window of the event log.
// This may be NULL if the caller does not wish to display any dump data.
// Flags Unused. Must be 0.
// pReserved Unused. Must be NULL.
//
// RETURNS:
// STATUS_SUCCESS If the bdliLogError call succeeded
//
NTSTATUS bdliLogError ( IN PVOID pObject, IN NTSTATUS ErrorCode, IN PUNICODE_STRING Insertion, IN ULONG cDumpData, IN PUCHAR pDumpData, IN ULONG Flags, IN PVOID pReserved ) { return (STATUS_SUCCESS); }
//
// bdliControlChange()
//
// This function allows BDDs to asynchronously return the values of its controls.
//
// bdliControlChange is generally called by the BDD in response to one of its controls
// changing a value. Specifically, it is most often used in the case of a sensor
// control that has changed from 0 to 1 indicating that a source is present and a sample
// can be taken.
//
// PARAMETERS:
// pBDLExt Pointer to the BDL_DEVICEEXT structure that was passed into the
// bdsiAddDevice call.
// ComponentId Specifies either the Component ID of the component in which the
// control or the control's parent channel resides, or '0' to indicate
// that dwControlId refers to a device control.
// ChannelId If dwComponentId is not '0', dwChannelId specifies either the Channel
// ID of the channel in which the control resides, or '0' to indicate
// that dwControlId refers to a component control.Ignored if
// dwComponentId is '0'.
// ControlId ControlId of the changed control.
// Value Specifies the new value for the control .
// Flags Unused. Must be 0.
// pReserved Unused. Must be NULL.
//
// RETURNS:
// STATUS_SUCCESS If the bdliControlChange call succeeded
//
NTSTATUS bdliControlChange ( IN PBDL_DEVICEEXT pBDLExt, IN ULONG ComponentId, IN ULONG ChannelId, IN ULONG ControlId, IN ULONG Value, IN ULONG Flags, IN PVOID pReserved ) { BDL_INTERNAL_DEVICE_EXTENSION *pBDLExtension = (BDL_INTERNAL_DEVICE_EXTENSION *) pBDLExt; ULONG i; KIRQL irql; ULONG TimeInSec = 0; LARGE_INTEGER CurrentTime;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!bdliControlChange: Enter\n", __DATE__, __TIME__))
KeAcquireSpinLock(&(pBDLExtension->ControlChangeStruct.ISRControlChangeLock), &irql);
//
// Save the current IRQ level so that when the DPC routine is executed it
// knows what level to elevate its IRQL to when getting an item from the
// ISRControlChangeQueue
//
pBDLExtension->ControlChangeStruct.ISRirql = KeGetCurrentIrql(); //
// Make sure the BDD isn't call us too often
//
if (pBDLExtension->ControlChangeStruct.NumCalls <= 8) { pBDLExtension->ControlChangeStruct.NumCalls++; } else { //
// FIX FIX - probably need to make this configurable (via registry) at some point
//
//
// We have received 10 notifies, make sure it has been longer than 1 second
//
KeQueryTickCount(&(CurrentTime));
TimeInSec = (ULONG) ((pBDLExtension->ControlChangeStruct.StartTime.QuadPart - CurrentTime.QuadPart) * KeQueryTimeIncrement() / 10000000);
if (TimeInSec == 0) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!bdliControlChange: BDD calling too often\n", __DATE__, __TIME__)) goto Return;
} else { pBDLExtension->ControlChangeStruct.NumCalls = 1; KeQueryTickCount(&(pBDLExtension->ControlChangeStruct.StartTime)); } }
//
// Get a free item from the pool
//
for (i = 0; i < CONTROL_CHANGE_POOL_SIZE; i++) { if (pBDLExtension->ControlChangeStruct.rgControlChangePool[i].fUsed == FALSE) { pBDLExtension->ControlChangeStruct.rgControlChangePool[i].fUsed = TRUE; //
// Add the item to the queue
//
InsertTailList( &(pBDLExtension->ControlChangeStruct.ISRControlChangeQueue), &(pBDLExtension->ControlChangeStruct.rgControlChangePool[i].ListEntry));
break; } }
if (i >= CONTROL_CHANGE_POOL_SIZE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!bdliControlChange: No free items\n", __DATE__, __TIME__))
goto Return; } pBDLExtension->ControlChangeStruct.rgControlChangePool[i].ComponentId = ComponentId; pBDLExtension->ControlChangeStruct.rgControlChangePool[i].ChannelId = ChannelId; pBDLExtension->ControlChangeStruct.rgControlChangePool[i].ControlId = ControlId; pBDLExtension->ControlChangeStruct.rgControlChangePool[i].Value = Value;
//
// Request a DPC. In the DPC we will move this notification from the
// ISRControlChangeQueue to the IOCTLControlChangeQueue
//
KeInsertQueueDpc(&(pBDLExtension->ControlChangeStruct.DpcObject), NULL, NULL);
Return:
KeReleaseSpinLock(&(pBDLExtension->ControlChangeStruct.ISRControlChangeLock), irql);
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!bdliControlChange: Leave\n", __DATE__, __TIME__))
return (STATUS_SUCCESS); }
VOID BDLControlChangeDpc ( IN PKDPC pDpc, IN BDL_INTERNAL_DEVICE_EXTENSION *pBDLExtension, IN PVOID pArg1, IN PVOID pArg2 ) { KIRQL oldIrql, irql; BDL_ISR_CONTROL_CHANGE_ITEM *pISRControlChangeItem = NULL; PLIST_ENTRY pISRControlChangeEntry = NULL; BDL_IOCTL_CONTROL_CHANGE_ITEM *pIOCTLControlChangeItem = NULL; PLIST_ENTRY pIOCTLControlChangeEntry = NULL; PIRP pIrpToComplete = NULL; PUCHAR pv = NULL;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLControlChangeDpc: Enter\n", __DATE__, __TIME__))
//
// Loop until there are no more items in the ISRControlChangeQueue
//
while (1) { //
// Allocate a new item to be added to the IOCTLControlChangeQueue
//
pIOCTLControlChangeItem = ExAllocatePoolWithTag( PagedPool, sizeof(BDL_IOCTL_CONTROL_CHANGE_ITEM), BDL_ULONG_TAG); if (pIOCTLControlChangeItem == NULL) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLControlChangeDpc: ExAllocatePoolWithTag failed\n", __DATE__, __TIME__)) return; }
//
// Need to raise the IRQL to access the ISRControlChangeQueue
//
KeRaiseIrql(pBDLExtension->ControlChangeStruct.ISRirql, &oldIrql); KeAcquireSpinLock(&(pBDLExtension->ControlChangeStruct.ISRControlChangeLock), &irql);
//
// Check to see if the ISRControlChangeQueue has any items
//
if (!IsListEmpty(&(pBDLExtension->ControlChangeStruct.ISRControlChangeQueue))) { //
// There is at least one item, so get the head of the queue
//
pISRControlChangeEntry = RemoveHeadList(&(pBDLExtension->ControlChangeStruct.ISRControlChangeQueue)); pISRControlChangeItem = CONTAINING_RECORD( pISRControlChangeEntry, BDL_ISR_CONTROL_CHANGE_ITEM, ListEntry);
pIOCTLControlChangeItem->ComponentId = pISRControlChangeItem->ComponentId; pIOCTLControlChangeItem->ChannelId = pISRControlChangeItem->ChannelId; pIOCTLControlChangeItem->ControlId = pISRControlChangeItem->ControlId; pIOCTLControlChangeItem->Value = pISRControlChangeItem->Value;
pISRControlChangeItem->fUsed = FALSE; } else { //
// There aren't any items in ISRControlChangeQueue, so set pIOCTLControlChangeItem
// to NULL which will indicate we are done with the loop
//
ExFreePoolWithTag(pIOCTLControlChangeItem, BDL_ULONG_TAG); pIOCTLControlChangeItem = NULL; }
KeReleaseSpinLock(&(pBDLExtension->ControlChangeStruct.ISRControlChangeLock), irql); KeLowerIrql(oldIrql);
if (pIOCTLControlChangeItem == NULL) { break; }
//
// Add the head of the ISRControlChangeQueue to the tail of the IOCTLControlChangeQueue
//
KeAcquireSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), &irql); InsertTailList( &(pBDLExtension->ControlChangeStruct.IOCTLControlChangeQueue), &(pIOCTLControlChangeItem->ListEntry)); KeReleaseSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), irql); }
//
// Now, if there is an item in the IOCTLControlChangeQueue and the GetNotification IRP
// is pending, complete the IRP with the head of the IOCTLControlChangeQueue
//
KeAcquireSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), &irql); if ((!IsListEmpty(&(pBDLExtension->ControlChangeStruct.IOCTLControlChangeQueue))) && (pBDLExtension->ControlChangeStruct.pIrp != NULL)) { pIOCTLControlChangeEntry = RemoveHeadList(&(pBDLExtension->ControlChangeStruct.IOCTLControlChangeQueue));
pIOCTLControlChangeItem = CONTAINING_RECORD( pIOCTLControlChangeEntry, BDL_IOCTL_CONTROL_CHANGE_ITEM, ListEntry);
pIrpToComplete = pBDLExtension->ControlChangeStruct.pIrp; pBDLExtension->ControlChangeStruct.pIrp = NULL; }
KeReleaseSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), irql);
if (pIrpToComplete != NULL) { pv = pIrpToComplete->AssociatedIrp.SystemBuffer;
*((ULONG *) pv) = pIOCTLControlChangeItem->ComponentId; pv += sizeof(ULONG); *((ULONG *) pv) = pIOCTLControlChangeItem->ChannelId; pv += sizeof(ULONG); *((ULONG *) pv) = pIOCTLControlChangeItem->ControlId; pv += sizeof(ULONG); *((ULONG *) pv) = pIOCTLControlChangeItem->Value;
ExFreePoolWithTag(pIOCTLControlChangeItem, BDL_ULONG_TAG);
pIrpToComplete->IoStatus.Information = SIZEOF_GETNOTIFICATION_OUTPUTBUFFER; pIrpToComplete->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(pIrpToComplete, IO_NO_INCREMENT); } BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLControlChangeDpc: Leave\n", __DATE__, __TIME__)) }
VOID BDLCleanupNotificationStruct ( IN BDL_INTERNAL_DEVICE_EXTENSION *pBDLExtension ) { KIRQL OldIrql, irql; BDL_ISR_CONTROL_CHANGE_ITEM *pISRControlChangeItem = NULL; PLIST_ENTRY pISRControlChangeEntry = NULL; BDL_IOCTL_CONTROL_CHANGE_ITEM *pIOCTLControlChangeItem = NULL; PLIST_ENTRY pIOCTLControlChangeEntry = NULL; BDL_CONTROL_CHANGE_REGISTRATION *pControlChangeRegistration = NULL; PLIST_ENTRY pRegistrationListEntry = NULL; BDDI_PARAMS_REGISTERNOTIFY bddiRegisterNotifyParams; NTSTATUS status;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLCleanupNotificationStruct: Enter\n", __DATE__, __TIME__))
bddiRegisterNotifyParams.fRegister = FALSE; //
// Clean up all the registered control changes
//
while (1) { //
// Note that we must raise the irql to dispatch level because we are synchronizing
// with a dispatch routine (BDLControlChangeDpc) that adds items to the queue at
// dispatch level
//
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); KeAcquireSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), &irql);
if (IsListEmpty(&(pBDLExtension->ControlChangeStruct.ControlChangeRegistrationList))) { //
// the lock we are currently holding will be released below
//
break; }
pRegistrationListEntry = RemoveHeadList(&(pBDLExtension->ControlChangeStruct.ControlChangeRegistrationList));
KeReleaseSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), irql); KeLowerIrql(OldIrql);
pControlChangeRegistration = CONTAINING_RECORD( pRegistrationListEntry, BDL_CONTROL_CHANGE_REGISTRATION, ListEntry);
bddiRegisterNotifyParams.ComponentId = pControlChangeRegistration->ComponentId; bddiRegisterNotifyParams.ChannelId = pControlChangeRegistration->ChannelId; bddiRegisterNotifyParams.ControlId = pControlChangeRegistration->ControlId; ExFreePoolWithTag(pControlChangeRegistration, BDL_ULONG_TAG);
//
// Call the BDD
//
status = pBDLExtension->pDriverExtension->bddiFunctions.pfbddiRegisterNotify( &(pBDLExtension->BdlExtenstion), &bddiRegisterNotifyParams); if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLCleanupNotificationStruct: pfbddiRegisterNotify failed with %lx\n", __DATE__, __TIME__, status)) //
// Just continue... nothing else we can do
//
} }
//
// Note: we are still holding the lock at this point
//
//
// Since we know there are no registered callbacks we should be able to clear up
// the ISRControlChangeQueue even though we are only running at dispatch level.
//
while (!IsListEmpty(&(pBDLExtension->ControlChangeStruct.ISRControlChangeQueue))) { pISRControlChangeEntry = RemoveHeadList(&(pBDLExtension->ControlChangeStruct.ISRControlChangeQueue));
pISRControlChangeItem = CONTAINING_RECORD( pISRControlChangeEntry, BDL_ISR_CONTROL_CHANGE_ITEM, ListEntry);
pISRControlChangeItem->fUsed = FALSE; } //
// Clean up IOCTLControlChangeQueue
//
while (!IsListEmpty(&(pBDLExtension->ControlChangeStruct.IOCTLControlChangeQueue))) { pIOCTLControlChangeEntry = RemoveHeadList(&(pBDLExtension->ControlChangeStruct.IOCTLControlChangeQueue));
pIOCTLControlChangeItem = CONTAINING_RECORD( pIOCTLControlChangeEntry, BDL_IOCTL_CONTROL_CHANGE_ITEM, ListEntry);
ExFreePoolWithTag(pIOCTLControlChangeItem, BDL_ULONG_TAG); }
KeReleaseSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), irql); KeLowerIrql(OldIrql);
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLCleanupNotificationStruct: Leave\n", __DATE__, __TIME__)) }
VOID BDLCleanupDataHandles ( IN BDL_INTERNAL_DEVICE_EXTENSION *pBDLExtension ) { NTSTATUS status; BDDI_ITEM *pBDDIItem = NULL; BDD_DATA_HANDLE bddDataHandle; BDDI_PARAMS_CLOSEHANDLE bddiCloseHandleParams; KIRQL irql;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLCleanupDataHandles: Enter\n", __DATE__, __TIME__))
bddiCloseHandleParams.Size = sizeof(bddiCloseHandleParams); BDLLockHandleList(pBDLExtension, &irql); //
// Go through each handle in the list and clean it up
//
while(BDLGetFirstHandle(&(pBDLExtension->HandleList), &bddDataHandle) == TRUE) { BDLRemoveHandleFromList(&(pBDLExtension->HandleList), bddDataHandle);
pBDDIItem = (BDDI_ITEM *) bddDataHandle;
//
// If this is a local handle then just clean it up, otherwise call the BDD
//
if (pBDDIItem->Type == BIO_ITEMTYPE_BLOCK) { bdliFree(pBDDIItem->Data.Block.pBuffer); } else { bddiCloseHandleParams.hData = pBDDIItem->Data.Handle; //
// Call the BDD
//
status = pBDLExtension->pDriverExtension->bddiFunctions.pfbddiCloseHandle( &(pBDLExtension->BdlExtenstion), &bddiCloseHandleParams); if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLCleanupDataHandles: pfbddiCloseHandle failed with %lx\n", __DATE__, __TIME__, status)) //
// Nothing we can do, just continue
//
} }
ExFreePoolWithTag(pBDDIItem, BDL_ULONG_TAG); } BDLReleaseHandleList(pBDLExtension, irql); BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLCleanupDataHandles: Leave\n", __DATE__, __TIME__)) }
|