|
|
// @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; }
|