You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3316 lines
95 KiB
3316 lines
95 KiB
/*++
|
|
|
|
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__))
|
|
}
|
|
|
|
|
|
|