Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1030 lines
33 KiB

// @doc
/**********************************************************************
*
* @module FLTR_PNP.C |
*
* Implementation of PnP and Power IRP handlers for Filter Device
* Objects.
*
* History
* ----------------------------------------------------------
* Mitchell S. Dernis Original
*
* (c) 1986-1998 Microsoft Corporation. All right reserved.
*
* @topic PNP |
* Power, Start, Stop, Remove Handlers. Shell like functionality
* only.
*
**********************************************************************/
#define __DEBUG_MODULE_IN_USE__ GCK_FLTR_PNP_C
extern "C"
{
#include <WDM.H>
#include "GckShell.h"
#include "debug.h"
//DECLARE_MODULE_DEBUG_LEVEL((DBG_WARN|DBG_ERROR|DBG_CRITICAL) );
DECLARE_MODULE_DEBUG_LEVEL((DBG_ALL) );
}
#include "SWVBENUM.h"
//---------------------------------------------------------------------------
// Alloc_text pragma to specify routines that can be paged out.
//---------------------------------------------------------------------------
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, GCK_FLTR_Power)
#pragma alloc_text (PAGE, GCK_FLTR_AddDevice)
#pragma alloc_text (PAGE, GCK_FLTR_PnP)
#pragma alloc_text (PAGE, GCK_FLTR_StartDevice)
#pragma alloc_text (PAGE, GCK_FLTR_StopDevice)
#pragma alloc_text (PAGE, GCK_GetHidInformation)
#pragma alloc_text (PAGE, GCK_CleanHidInformation)
#endif
/***********************************************************************************
**
** NTSTATUS GCK_FLTR_Power (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
**
** @func Handles IRP_MJ_POWER for Filter Device Objects
**
** @rdesc STATUS_SUCCESS, or various errors
**
*************************************************************************************/
NTSTATUS GCK_FLTR_Power
(
IN PDEVICE_OBJECT pDeviceObject, // @parm Device Object for our context
IN PIRP pIrp // @parm IRP to handle
)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PGCK_FILTER_EXT pFilterExt;
PAGED_CODE ();
GCK_DBG_ENTRY_PRINT(("Entering GCK_FLTR_Power. pDO = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp));
pFilterExt = (PGCK_FILTER_EXT)pDeviceObject->DeviceExtension;
GCK_IncRemoveLock(&pFilterExt->RemoveLock);
// If we have been removed we need to refuse this IRP
if (GCK_STATE_REMOVED == pFilterExt->eDeviceState) {
GCK_DBG_TRACE_PRINT(("GCK_Power called while delete pending\n"));
//Fill in IO_STATUS_BLOCK with failure
NtStatus = STATUS_DELETE_PENDING;
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = NtStatus;
// Tell system that we are ready for another power IRP
PoStartNextPowerIrp(pIrp);
//Complete IRP with failure
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
}
else //Pass it down to next driver
{
GCK_DBG_TRACE_PRINT(("Sending Power IRP down to next driver\n"));
// Tell system we are ready for the next power IRP
PoStartNextPowerIrp (pIrp);
// NOTE!!! PoCallDriver NOT IoCallDriver.
IoSkipCurrentIrpStackLocation (pIrp);
NtStatus = PoCallDriver (pFilterExt->pTopOfStack, pIrp);
}
// Decrement outstanding IRP count, and signal if it want to zero
GCK_DecRemoveLock(&pFilterExt->RemoveLock);
GCK_DBG_EXIT_PRINT(("Exiting GCK_FLTR_Power. Status: 0x%0.8x\n", NtStatus));
return NtStatus;
}
/***********************************************************************************
**
** NTSTATUS GCK_FLTR_AddDevice(IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT pPhysicalDeviceObject)
**
** @func Handles AddDevice calls from PnP system, create filter device and
** attach to top of stack. Note this is a direct entry, as control, and SWVB
** have not this function and it is a good thing too, as we would have little
** idea of what to Add.
** @rdesc STATUS_SUCCES, or various errors
**
*************************************************************************************/
NTSTATUS GCK_FLTR_AddDevice
(
IN PDRIVER_OBJECT pDriverObject, // @parm Driver object to create filter device for
IN PDEVICE_OBJECT pPhysicalDeviceObject // @parm PDO for device to create
)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PDEVICE_OBJECT pDeviceObject = NULL;
PGCK_FILTER_EXT pFilterExt = NULL;
PAGED_CODE ();
GCK_DBG_ENTRY_PRINT(("Entering GCK_FLTR_AddDevice, pDriverObject = 0x%0.8x, pPDO = 0x%0.8x\n", pDriverObject, pPhysicalDeviceObject));
//
// If there is not a Global Control Device create one
// (The global control object is for programming the filter. When the
// first filter device is created, we create one. When the last filter
// device is removed, we remove it.)
//
if(!Globals.pControlObject)
{
GCK_CTRL_AddDevice( pDriverObject );
}
//
// Create a filter device object.
//
GCK_DBG_TRACE_PRINT(("Creating Filter Device\n"));
NtStatus = IoCreateDevice (pDriverObject,
sizeof (GCK_FILTER_EXT),
NULL, // No Name
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&pDeviceObject);
if (!NT_SUCCESS (NtStatus)) {
//
// returning failure here prevents the entire stack from functioning,
// but most likely the rest of the stack will not be able to create
// device objects either, so it is still OK.
//
GCK_DBG_CRITICAL_PRINT(("Failed to create filter device object\n"));
GCK_DBG_EXIT_PRINT(("Exiting AddDevice(1) Status: 0x%0.8x\n", NtStatus));
return NtStatus;
}
//
// Initialize the the device extension.
//
GCK_DBG_TRACE_PRINT(("Initializing Filter's Device Extension\n"));
pFilterExt = (PGCK_FILTER_EXT)pDeviceObject->DeviceExtension; //Get pointer to extension
pFilterExt->ulGckDevObjType = GCK_DO_TYPE_FILTER; //Put our name on this, so we can speak for it later
pFilterExt->eDeviceState = GCK_STATE_STOPPED; //Device starts out stopped
pFilterExt->pPDO = pPhysicalDeviceObject; //Remember our PDO
pFilterExt->pTopOfStack = NULL; //We are not attached to stack yet
GCK_InitRemoveLock(&pFilterExt->RemoveLock, "Filter PnP"); //Initialize Remove Lock
pFilterExt->pvForceIoctlQueue = NULL; // There is no Queue unless force requests come in
pFilterExt->pvTriggerIoctlQueue = NULL; // There is no Queue unless trigger requests come in
// !!!!!! Need to clean up the above Queues
//we use the same IO method as hidclass.sys, which DO_DIRECT_IO
pDeviceObject->StackSize = pPhysicalDeviceObject->StackSize + 1;
pDeviceObject->Flags |= (DO_DIRECT_IO | DO_POWER_PAGABLE);
pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
GCK_DBG_TRACE_PRINT(("FDO flags set to %x\n", pDeviceObject->Flags));
//
// Add new Device Object to List of Objects
//
GCK_DBG_TRACE_PRINT(("Adding new filter device object to global linked list\n"));
ExAcquireFastMutex(&Globals.FilterObjectListFMutex);
//Add item to head as it is fastest place to add
pFilterExt->pNextFilterObject=Globals.pFilterObjectList;
Globals.pFilterObjectList = pDeviceObject; //Add the whole object not just the extension
Globals.ulFilteredDeviceCount++; //Increment count of filtered devices
ExReleaseFastMutex(&Globals.FilterObjectListFMutex);
//
// Make sure the internal POLL is ready for open and close
//
GCK_IP_AddDevice(pFilterExt);
//
// Attach our filter driver to the device stack.
// the return value of IoAttachDeviceToDeviceStack is the top of the
// attachment chain. This is where all the IRPs should be routed.
//
// Our filter will send IRPs to the top of the stack and use the PDO
// for all PlugPlay functions.
GCK_DBG_TRACE_PRINT(("Attaching to top of device stack\n"));
pFilterExt->pTopOfStack = IoAttachDeviceToDeviceStack (pDeviceObject, pPhysicalDeviceObject);
//
// if this attachment fails then top of stack will be null.
// failure for attachment is an indication of a broken plug play system.
//
ASSERT (NULL != pFilterExt->pTopOfStack);
GCK_DBG_TRACE_PRINT(( "pTopOfStack = 0x%0.8x", pFilterExt->pTopOfStack ));
//
// Assure that the Virtual Bus has a Device Object to sit on.
// To fix bug 1018, which would also have other implications, this is moved to start device
// to start device
//
//if( !Globals.pSWVB_FilterExt )
//{
// Globals.pSWVB_FilterExt = pFilterExt;
// NtStatus = GCK_SWVB_SetBusDOs(pDeviceObject, pPhysicalDeviceObject);
// //At this point GCK_SWVB_SetBusDOs only returns STATUS_SUCCESS, it should return void
// ASSERT( STATUS_SUCCESS == NtStatus);
//}
GCK_DBG_EXIT_PRINT(("Exiting AddDevice(2) Status: STATUS_SUCCESS\n"));
return STATUS_SUCCESS;
}
/***********************************************************************************
**
** NTSTATUS GCK_FLTR_PnP(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
**
** @func Handles IRP_MJ_PNP for Filter Devices, dispatchs
** IRPs for Control Devices or Virtual Devices elsewhere.
**
** @rdesc STATUS_SUCCESS, or various errors
**
*************************************************************************************/
NTSTATUS GCK_FLTR_PnP
(
IN PDEVICE_OBJECT pDeviceObject, // @parm Device Object for our context
IN PIRP pIrp // @parm IRP to handle
)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PGCK_FILTER_EXT pFilterExt;
PIO_STACK_LOCATION pIrpStack;
PDEVICE_OBJECT *ppPrevDeviceObjectPtr;
PDEVICE_OBJECT pCurDeviceObject;
//PGCK_FILTER_EXT pCurFilterExt;
BOOLEAN fRemovedFromList;
BOOLEAN fFoundOne;
PAGED_CODE ();
GCK_DBG_ENTRY_PRINT(("Entering GCK_FLTR_PnP. pDO = 0x%0.8x, pIrp = 0x%0.8x\n", pDeviceObject, pIrp));
//cast device extension to proper type
pFilterExt = (PGCK_FILTER_EXT) pDeviceObject->DeviceExtension;
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
// Just an extra sanity check - before accessing extension
ASSERT( GCK_DO_TYPE_FILTER == pFilterExt->ulGckDevObjType);
//Increment Remove Lock while handling this IRP
GCK_IncRemoveLock(&pFilterExt->RemoveLock);
//
// If we have been removed we need to refuse this IRP, this should
// never happen with PnP IRPs
//
if (GCK_STATE_REMOVED == pFilterExt->eDeviceState) {
GCK_DBG_TRACE_PRINT(("GCK_FLTR_PnP called while delete pending\n"));
ASSERT(FALSE);
NtStatus = STATUS_DELETE_PENDING;
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = NtStatus;
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
}
else // we need to handle it
{
switch (pIrpStack->MinorFunction) {
case IRP_MN_CANCEL_STOP_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_CANCEL_STOP_DEVICE - Fall through to IRP_MN_START_DEVICE\n"));
ASSERT(GCK_STATE_STOP_PENDING == pFilterExt->eDeviceState);
pFilterExt->eDeviceState = GCK_STATE_STARTED;
case IRP_MN_CANCEL_REMOVE_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_CANCEL_REMOVE_DEVICE - Fall through to IRP_MN_START_DEVICE\n"));
case IRP_MN_START_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_START_DEVICE\n"));
// The device is starting. Lower level drivers need to start first
IoCopyCurrentIrpStackLocationToNext (pIrp);
KeInitializeEvent(&pFilterExt->StartEvent, NotificationEvent, FALSE);
// Set Completion routine to signal when done
IoSetCompletionRoutine (
pIrp,
GCK_FLTR_PnPComplete,
pFilterExt,
TRUE,
TRUE,
TRUE
);
// Send down the IRP
GCK_DBG_TRACE_PRINT(("Calling lower driver\n"));
NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp);
// Wait for it to complete
if (STATUS_PENDING == NtStatus)
{
KeWaitForSingleObject(
&pFilterExt->StartEvent, // waiting for Completion of Start
Executive, // Waiting for reason of a driver
KernelMode, // Waiting in kernel mode
FALSE, // No alert
NULL // No timeout
);
}
// Remember the status of the lower driver
NtStatus = pIrp->IoStatus.Status;
//In the case of a cancel stop, the lower driver may not support it.
//we still need to restart
if(NT_SUCCESS (NtStatus) || STATUS_NOT_SUPPORTED==NtStatus)
{
//
// As we are successfully now back from lower driver
// our start device can do work.
//
NtStatus = GCK_FLTR_StartDevice (pDeviceObject, pIrp);
}
//
// We must now complete the IRP, since we stopped it in the
// completetion routine with MORE_PROCESSING_REQUIRED.
//
if (!NT_SUCCESS (NtStatus))
{
if (pIrpStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE)
{
NtStatus = STATUS_SUCCESS; // Not allow to fail this!
}
}
pIrp->IoStatus.Status = NtStatus;
pIrp->IoStatus.Information = 0;
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
break;
case IRP_MN_QUERY_STOP_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_QUERY_STOP_DEVICE\n"));
ASSERT( GCK_STATE_STARTED == pFilterExt->eDeviceState);
pFilterExt->eDeviceState = GCK_STATE_STOP_PENDING;
//Close Handle to driver beneath
NtStatus = GCK_IP_CloseFileObject(pFilterExt);
if( NT_SUCCESS (NtStatus) )
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation (pIrp);
NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp);
}
else
{
pIrp->IoStatus.Status = NtStatus;
pIrp->IoStatus.Information = 0;
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
}
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_QUERY_REMOVE_DEVICE - Fall through to IRP_MN_STOP_DEVICE\n"));
case IRP_MN_SURPRISE_REMOVAL:
GCK_DBG_TRACE_PRINT(("IRP_MN_SURPRISE_REMOVAL - Fall through to IRP_MN_STOP_DEVICE\n"));
case IRP_MN_STOP_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_STOP_DEVICE\n"));
// Do whatever processing is required
GCK_FLTR_StopDevice (pFilterExt, TRUE);
// We don't need a completion routine so fire and forget.
GCK_DBG_TRACE_PRINT(("Calling lower driver\n"));
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation (pIrp);
NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp);
break;
case IRP_MN_REMOVE_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_REMOVE_DEVICE\n"));
//@todo All the code in this case, should be moved to a separate function
// Note! we might receive a remove WITHOUT first receiving a stop.
if(
GCK_STATE_STARTED == pFilterExt->eDeviceState ||
GCK_STATE_STOP_PENDING == pFilterExt->eDeviceState
)
{
// Stop the device without touching the hardware.
GCK_FLTR_StopDevice(pFilterExt, FALSE);
}
//
// We will no longer receive requests for this device as it has been
// removed. (Note some code below, depends on this flag being updated.)
//
pFilterExt->eDeviceState = GCK_STATE_REMOVED;
// Send on the remove IRP
// Set the Status before sending the IRP onwards
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation (pIrp);
NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp);
// Undo our increment upon entry to this routine
GCK_DecRemoveLock(&pFilterExt->RemoveLock);
// Undo the bias Wait for count to go to zero, forever.
GCK_DecRemoveLockAndWait(&pFilterExt->RemoveLock, NULL);
//
// Now that we are sure that outstanding IRPs are done,
// we remove ourselves from the drivers global list of devices
//
GCK_DBG_TRACE_PRINT(("Removing from global linked list.\n"));
// Acquire mutext to touch global list
ExAcquireFastMutex(&Globals.FilterObjectListFMutex);
// Remove device from linked list of device that we handle
ppPrevDeviceObjectPtr = &Globals.pFilterObjectList;
pCurDeviceObject = Globals.pFilterObjectList;
fRemovedFromList = FALSE;
while( pCurDeviceObject )
{
if( pCurDeviceObject == pDeviceObject )
{
// Remove us from list
*ppPrevDeviceObjectPtr = NEXT_FILTER_DEVICE_OBJECT(pCurDeviceObject);
fRemovedFromList = TRUE;
break;
}
else
{
//skip to the next object
ppPrevDeviceObjectPtr = PTR_NEXT_FILTER_DEVICE_OBJECT(pCurDeviceObject);
pCurDeviceObject = NEXT_FILTER_DEVICE_OBJECT(pCurDeviceObject);
}
}
ASSERT(fRemovedFromList);
if(fRemovedFromList)
{
Globals.ulFilteredDeviceCount--; //Decrement count of filtered devices
}
//Set fFoundOne TRUE if there are any device left
fFoundOne = Globals.ulFilteredDeviceCount ? TRUE : FALSE;
// Release mutex to touch global list
ExReleaseFastMutex(&Globals.FilterObjectListFMutex);
//If there are no more devices left, cleanup Global Control Device
//Verify that Virtual Bus has deleted any straggling Device Objects
if(!fFoundOne)
{
GCK_CTRL_Remove();
}
GCK_DBG_TRACE_PRINT(("Detaching and Deleting DeviceObject.\n"));
IoDetachDevice (pFilterExt->pTopOfStack); //Detach from top of stack
IoDeleteDevice (pDeviceObject); //Delete ourselves
// Must succeed this
GCK_DBG_EXIT_PRINT(("Exiting GCK_FLTR_PnP(1) with status 0x%08x\n", NtStatus));
ASSERT( NT_SUCCESS( NtStatus ) );
return NtStatus;
case IRP_MN_QUERY_DEVICE_RELATIONS:
//
// We may be the platform for the virtual bus, if we are
// we need to call GCK_SWVB_BusRelations
//
GCK_DBG_TRACE_PRINT(("IRP_MN_QUERY_DEVICE_RELATIONS\n"));
if(
(BusRelations == pIrpStack->Parameters.QueryDeviceRelations.Type) &&
(pFilterExt == Globals.pSWVB_FilterExt)
)
{
NtStatus = GCK_SWVB_HandleBusRelations(&pIrp->IoStatus);
// If an error occured, stop it here and send it back;
if( NT_ERROR(NtStatus) )
{
GCK_DBG_CRITICAL_PRINT(("GCK_SWVB_BusRelations returned 0x%0.8x, completing the IRP\n", NtStatus));
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
break;
}
}
// Pass it along
IoSkipCurrentIrpStackLocation (pIrp);
NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp);
break;
case IRP_MN_QUERY_INTERFACE:
case IRP_MN_QUERY_CAPABILITIES:
case IRP_MN_QUERY_RESOURCES:
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
case IRP_MN_READ_CONFIG:
case IRP_MN_WRITE_CONFIG:
case IRP_MN_EJECT:
case IRP_MN_SET_LOCK:
case IRP_MN_QUERY_ID:
case IRP_MN_QUERY_PNP_DEVICE_STATE:
default:
// All of these just pass on
GCK_DBG_TRACE_PRINT(("Irp Minor Code 0x%0.8x: Calling lower driver.\n", pIrpStack->MinorFunction));
IoSkipCurrentIrpStackLocation (pIrp);
NtStatus = IoCallDriver (pFilterExt->pTopOfStack, pIrp);
break;
}
}
GCK_DecRemoveLock(&pFilterExt->RemoveLock);
GCK_DBG_EXIT_PRINT(("Exiting GCK_FLTR_PnP(2) with Status, 0x%0.8x\n", NtStatus));
return NtStatus;
}
/***********************************************************************************
**
** NTSTATUS GCK_FLTR_PnPComplete (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID pContext)
**
** @func Completion for IRP_MJ_PNP\IR_MN_START_DEVICE for Filter Devices
** Used mainly for start device. Since it may be called at IRQL = LEVEL_DISPATCH
** cannot be pageable!
** @rdesc STATUS_MORE_PROCESSING_REQUIRED
**
*************************************************************************************/
NTSTATUS GCK_FLTR_PnPComplete
(
IN PDEVICE_OBJECT pDeviceObject, // @parm DeviceObject as our context
IN PIRP pIrp, // @parm IRP to complete
IN PVOID pContext // @parm Not used
)
{
PGCK_FILTER_EXT pFilterExt;
NTSTATUS NtStatus = STATUS_SUCCESS;
//
// Current stack location is needed for DEBUG assertion only
//
#if (DBG==1)
PIO_STACK_LOCATION pIrpStack;
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
#endif
GCK_DBG_ENTRY_PRINT((
"Entering GCK_FLTR_PnPComplete. pDO = 0x%0.8x, pIrp = 0x%0.8x, pContext = 0x%0.8x\n",
pDeviceObject,
pIrp,
pContext
));
UNREFERENCED_PARAMETER (pDeviceObject);
if (pIrp->PendingReturned)
{
IoMarkIrpPending( pIrp );
}
pFilterExt = (PGCK_FILTER_EXT) pContext;
KeSetEvent (&pFilterExt->StartEvent, 0, FALSE);
GCK_DBG_EXIT_PRINT(("Exiting GCK_FLTR_PnPComplete with STATUS_MORE_PROCESSING_REQUIRED\n"));
return STATUS_MORE_PROCESSING_REQUIRED;
}
/***********************************************************************************
**
** NTSTATUS GCK_FLTR_StartDevice (IN PGCK_FILTER_EXT pFilterExt, IN PIRP pIrp)
**
** @func On IRP_MN_START_DEVICE attaches filter module, creates
**
** @rdesc STATUS_SUCCESS, or various errors
**
*************************************************************************************/
NTSTATUS GCK_FLTR_StartDevice
(
IN PDEVICE_OBJECT pDeviceObject, // @parm pointer to device object
IN PIRP pIrp // @parm IRP to handle
)
{
NTSTATUS NtStatus;
LARGE_INTEGER lgiBufferOffset;
UNREFERENCED_PARAMETER (pIrp);
PAGED_CODE ();
PGCK_FILTER_EXT pFilterExt = (PGCK_FILTER_EXT) pDeviceObject->DeviceExtension;
GCK_DBG_ENTRY_PRINT((
"Entering GCK_StartDevice. pFilterExt = 0x%0.8x, pIrp = 0x%0.8x\n",
pFilterExt,
pIrp
));
//
// We shouldn't get a start on a removed device
//
ASSERT(GCK_STATE_REMOVED != pFilterExt->eDeviceState);
//
// We shouldn't try to start a device that is already started
//
if (
GCK_STATE_STARTED == pFilterExt->eDeviceState ||
GCK_STATE_STOP_PENDING == pFilterExt->eDeviceState
)
{
GCK_DBG_WARN_PRINT(( "Two IRP_MN_START_DEVICE recieved.\n"));
GCK_DBG_EXIT_PRINT(("Exiting GCK_FLTR_StartDevice(1) with STATUS_SUCCESS\n"));
return STATUS_SUCCESS;
}
//
// Put the virtual bus on top of us if it is not already
//
ExAcquireFastMutex(&Globals.FilterObjectListFMutex);
if( !Globals.pSWVB_FilterExt )
{
Globals.pSWVB_FilterExt = pFilterExt;
NtStatus = GCK_SWVB_SetBusDOs(pDeviceObject, pFilterExt->pPDO);
ASSERT( STATUS_SUCCESS == NtStatus);
}
ExReleaseFastMutex(&Globals.FilterObjectListFMutex);
//
// Collect basic info about the device
//
NtStatus = GCK_GetHidInformation(pFilterExt);
//
// Initialize filter hooks
//
if( NT_SUCCESS(NtStatus) )
{ // We can't initialize if we don't have hid info (vidpid!)
GCKF_InitFilterHooks(pFilterExt);
}
// Allocate a Buffer for last known poll of the device
if( NT_SUCCESS(NtStatus) )
{
pFilterExt->pucLastReport = (PUCHAR) EX_ALLOCATE_POOL
( NonPagedPool,
pFilterExt->HidInfo.HidPCaps.InputReportByteLength );
if(!pFilterExt->pucLastReport)
{
GCK_DBG_CRITICAL_PRINT(("Failed to allocate Report Buffer for last known report\n"));
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
// Initialize last known status for very first IRP
if( NT_SUCCESS(NtStatus) )
{
pFilterExt->ioLastReportStatus.Information = (ULONG)pFilterExt->HidInfo.HidPCaps.InputReportByteLength;
pFilterExt->ioLastReportStatus.Status = STATUS_SUCCESS;
}
if ( NT_SUCCESS(NtStatus) )
{
//Initialize InternalPoll module
NtStatus = GCK_IP_Init(pFilterExt);
}
// Mark device as Started
if ( NT_SUCCESS(NtStatus) )
{
//mark for full time polling, but understand
//that it won't start yet.
GCK_IP_FullTimePoll(pFilterExt, TRUE);
pFilterExt->eDeviceState = GCK_STATE_STARTED;
// Set device specific initial mapping in case
// the value add is not running
GCKF_SetInitialMapping( pFilterExt );
}
else // we failed somewhere, clean up to mark as started
{
GCK_DBG_TRACE_PRINT(("Cleaning up in event of failure\n"));
//Cleanup internal polling module
GCK_IP_Cleanup(pFilterExt);
// No need to check if buffer was created, if it was we succeeded
if(pFilterExt->pucLastReport)
{
ExFreePool(pFilterExt->pucLastReport);
pFilterExt->pucLastReport = NULL;
}
// Call CleanHidInformation to free anything allocated
// and zero it out
GCK_CleanHidInformation( pFilterExt );
}
GCK_DBG_EXIT_PRINT(("Exiting GCK_FLTR_StartDevice(2) with Status: 0x%0.8x\n", NtStatus));
return NtStatus;
}
/***********************************************************************************
**
** VOID GCK_StopDevice (IN PGCK_FILTER_EXT pFilterExt, IN BOOLEAN fTouchTheHardware)
**
** @func Cancel outstanding IRPs and frees private Ping-Pong IRP
**
*************************************************************************************/
VOID GCK_FLTR_StopDevice
(
IN PGCK_FILTER_EXT pFilterExt, // @parm Device Extension
IN BOOLEAN fTouchTheHardware // @parm TRUE if hardware can be touched
// - unused we never touch hardware
)
{
BOOLEAN fCanceled;
UNREFERENCED_PARAMETER(fTouchTheHardware);
GCK_DBG_ENTRY_PRINT(("Entry GCK_FLTR_StopDevice, pFilterExt = 0x%0.8x\n", pFilterExt));
PAGED_CODE ();
ASSERT(GCK_STATE_STOPPED != pFilterExt->eDeviceState);
if(GCK_STATE_STOPPED == pFilterExt->eDeviceState) return;
//stop internal polling
GCK_IP_FullTimePoll(pFilterExt, FALSE);
// Mark device as stopped
pFilterExt->eDeviceState = GCK_STATE_STOPPED;
//Cleanup internal polling module
GCK_IP_Cleanup(pFilterExt);
if (pFilterExt->pFilterHooks!=NULL) GCKF_DestroyFilterHooks(pFilterExt);
//Acquire mutex to access list of filter objects
ExAcquireFastMutex(&Globals.FilterObjectListFMutex);
if( Globals.pSWVB_FilterExt == pFilterExt)
{
//Walk linked list of Filter Device Objects, looking for one that is not stopped
BOOLEAN fFoundOne = FALSE;
PDEVICE_OBJECT pCurDeviceObject = Globals.pFilterObjectList;
PGCK_FILTER_EXT pCurFilterExt;
NTSTATUS NtStatus;
while( pCurDeviceObject )
{
pCurFilterExt = (PGCK_FILTER_EXT)pCurDeviceObject->DeviceExtension;
if(
GCK_STATE_STARTED == pCurFilterExt->eDeviceState ||
GCK_STATE_STOP_PENDING == pCurFilterExt->eDeviceState
)
{
NtStatus = GCK_SWVB_SetBusDOs(pCurDeviceObject, pCurFilterExt->pPDO);
ASSERT( NT_SUCCESS(NtStatus) );
if( NT_SUCCESS(NtStatus) )
{
fFoundOne = TRUE;
Globals.pSWVB_FilterExt = pCurFilterExt;
break;
}
}
//skip to the next object
pCurDeviceObject = pCurFilterExt->pNextFilterObject;
}
if( !fFoundOne )
{
//Didn't find a place to hang the bus so move it nowhere
NtStatus = GCK_SWVB_SetBusDOs(NULL, NULL);
ASSERT( NT_SUCCESS(NtStatus) );
Globals.pSWVB_FilterExt = NULL;
}
}
//Release mutex to access list of filter objects
ExReleaseFastMutex(&Globals.FilterObjectListFMutex);
//
// Free any structures relating to device (if needed)
//
if(pFilterExt->pucLastReport)
{
ExFreePool(pFilterExt->pucLastReport);
pFilterExt->pucLastReport = NULL;
}
GCK_CleanHidInformation( pFilterExt );
GCK_DBG_EXIT_PRINT(("Exiting GCK_FLTR_StopDevice\n"));
}
/***********************************************************************************
**
** NTSTATUS GCK_GetHidInformation(IN PGCK_FILTER_EXT pFilterExt)
**
** @func Does IOCTL_HID_GET_COLLECTION_INFORMATION to fill in
** GCK_HID_DEVICE_INFO in DeviceExtension
**
** @rdesc STATUS_SUCCESS
**
*************************************************************************************/
NTSTATUS GCK_GetHidInformation
(
IN PGCK_FILTER_EXT pFilterExt // @parm Device Extension for filter
)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
KEVENT HidCompletionEvent;
PIRP pHidIrp;
IO_STATUS_BLOCK ioStatus;
PAGED_CODE ();
GCK_DBG_ENTRY_PRINT(( "Entering GCK_GetHidInformation. pFilterExt = 0x%0.8x\n", pFilterExt));
//
// Initialize Event for synchronous call to device
//
KeInitializeEvent(&HidCompletionEvent, NotificationEvent, FALSE);
//**
//** IOCTL_HID_GET_COLLECTION_INFORMATION
//**
//
// Setup IRP
//
pHidIrp =
IoBuildDeviceIoControlRequest(
IOCTL_HID_GET_COLLECTION_INFORMATION,
pFilterExt->pTopOfStack,
NULL,
0,
&pFilterExt->HidInfo.HidCollectionInfo,
sizeof (HID_COLLECTION_INFORMATION),
FALSE, /* EXTERNAL */
&HidCompletionEvent,
&ioStatus
);
if( NULL == pHidIrp)
{
GCK_DBG_CRITICAL_PRINT(("Failed to allocate IRP for IOCTL_HID_GET_COLLECTION_INFORMATION\n"));
GCK_DBG_EXIT_PRINT(("Exiting GCK_GetHidInformation(1) returning STATUS_INSUFFICIENT_RESOURCES\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Call Driver
//
NtStatus = IoCallDriver(pFilterExt->pTopOfStack, pHidIrp);
GCK_DBG_TRACE_PRINT(("IoCallDriver returned 0x%0.8x\n", NtStatus));
//
// Wait for IRP to complete
//
if (STATUS_PENDING == NtStatus)
{
GCK_DBG_TRACE_PRINT(("Waiting for IOCTL_HID_GET_COLLECTION_INFORMATION to complete\n"));
NtStatus = KeWaitForSingleObject(
&HidCompletionEvent,
Executive,
KernelMode,
FALSE,
NULL
);
}
if( NT_ERROR( NtStatus) )
{
GCK_DBG_CRITICAL_PRINT(("Failed IRP for IOCTL_HID_GET_COLLECTION_INFORMATION\n"));
GCK_DBG_EXIT_PRINT(("Exiting GCK_GetHidInformation(2) returning 0x%0.8x\n", NtStatus));
return NtStatus;
}
//**
//** Get HID_PREPARSED_DATA
//**
//
// Allocate space for HIDP_PREPARSED_DATA, and zero memory
//
pFilterExt->HidInfo.pHIDPPreparsedData =
(PHIDP_PREPARSED_DATA)
EX_ALLOCATE_POOL(
NonPagedPool,
pFilterExt->HidInfo.HidCollectionInfo.DescriptorSize
);
if( !pFilterExt->HidInfo.pHIDPPreparsedData )
{
GCK_DBG_CRITICAL_PRINT(("Failed to allocate IRP for IOCTL_HID_GET_COLLECTION_DESCRIPTOR\n"));
GCK_DBG_EXIT_PRINT(("Exiting GCK_GetHidInformation(3) returning STATUS_INSUFFICIENT_RESOURCES\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(
pFilterExt->HidInfo.pHIDPPreparsedData,
pFilterExt->HidInfo.HidCollectionInfo.DescriptorSize
);
//
// Clear Synchronization Event
//
KeClearEvent(&HidCompletionEvent);
//
// Setup IRP
//
pHidIrp =
IoBuildDeviceIoControlRequest(
IOCTL_HID_GET_COLLECTION_DESCRIPTOR,
pFilterExt->pTopOfStack,
NULL,
0,
pFilterExt->HidInfo.pHIDPPreparsedData,
pFilterExt->HidInfo.HidCollectionInfo.DescriptorSize,
FALSE, /* EXTERNAL */
&HidCompletionEvent,
&ioStatus
);
if( NULL == pHidIrp)
{
ExFreePool( (PVOID)pFilterExt->HidInfo.pHIDPPreparsedData);
pFilterExt->HidInfo.pHIDPPreparsedData = NULL;
GCK_DBG_CRITICAL_PRINT(("Failed to allocate IRP for IOCTL_HID_GET_COLLECTION_DESCRIPTOR\n"));
GCK_DBG_EXIT_PRINT(("Exiting GCK_GetHidInformation(4) returning STATUS_INSUFFICIENT_RESOURCES\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
// Call Driver
NtStatus = IoCallDriver(pFilterExt->pTopOfStack, pHidIrp);
GCK_DBG_TRACE_PRINT(("IoCallDriver returned 0x%0.8x\n", NtStatus));
//
// Wait for IRP to complete
//
if (STATUS_PENDING == NtStatus)
{
GCK_DBG_TRACE_PRINT(("Waiting for IOCTL_HID_GET_COLLECTION_DESCRIPTOR to complete\n"));
NtStatus = KeWaitForSingleObject(
&HidCompletionEvent,
Executive,
KernelMode,
FALSE,
NULL
);
}
if( NT_ERROR( NtStatus) )
{
ExFreePool( (PVOID)pFilterExt->HidInfo.pHIDPPreparsedData);
pFilterExt->HidInfo.pHIDPPreparsedData = NULL;
GCK_DBG_CRITICAL_PRINT(("Failed IRP for IOCTL_HID_GET_COLLECTION_DESCRIPTOR\n"));
GCK_DBG_EXIT_PRINT(("Exiting GCK_GetHidInformation(5) returning 0x%0.8x\n", NtStatus));
return NtStatus;
}
//**
//** Get HIDP_CAPS structure
//**
NtStatus = HidP_GetCaps(pFilterExt->HidInfo.pHIDPPreparsedData, &pFilterExt->HidInfo.HidPCaps);
GCK_DBG_EXIT_PRINT(("Exiting GCK_GetHidInformation(6). Status = 0x%0.8x\n", NtStatus));
return NtStatus;
}
/***********************************************************************************
**
** VOID GCK_CleanHidInformation( IN PGCK_FILTER_EXT pFilterExt)
**
** @func Cleans up GCK_HID_INFORMATION in device extension
**
*************************************************************************************/
VOID GCK_CleanHidInformation(
IN PGCK_FILTER_EXT pFilterExt // @parm Device Extension
)
{
PAGED_CODE ();
GCK_DBG_ENTRY_PRINT(("Entering GCK_CleanHidInformation\n"));
//
// Free preparsed data, if necessary
//
if(pFilterExt->HidInfo.pHIDPPreparsedData)
{
GCK_DBG_TRACE_PRINT(("Freeing pHIDPPreparsedData\n"));
ExFreePool( (PVOID)pFilterExt->HidInfo.pHIDPPreparsedData);
pFilterExt->HidInfo.pHIDPPreparsedData = NULL;
}
//
// Zero out all of the Hid Info
//
RtlZeroMemory(
(PVOID)&pFilterExt->HidInfo,
sizeof(GCK_HID_DEVICE_INFO)
);
GCK_DBG_EXIT_PRINT(("Exiting GCK_CleanHidInformation\n"));
return;
}