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.
 
 
 
 
 
 

731 lines
23 KiB

// @doc
/**********************************************************************
*
* @module InternalPolling.c |
*
* Implementation of routines for internal polling
*
* History
* ----------------------------------------------------------
* Mitchell S. Dernis Original
*
* (c) 1986-1999 Microsoft Corporation. All right reserved.
*
* @topic Internal Polling |
* All polling to get data is via this internal polling mechanism.
* However, for security and access checks, the first poll from
* a new file handle is sent straight down, and comes up via
* different completion. To keep track of this we keep a linked
* list of GCK_FILE_OPEN_ITEMs representing each of the FILE_OBJECTS
* that we need.<nl>
* To Poll internally we need to have a valid FILE_OBJECT otherwise
* hidclass.sys will reject the poll request. This is done
* via GCK_IP_CreateFileObject which internally calls IoGetDeviceObjectPointer.
* Somewhat unfortunately, this takes circular path through, so is not
* really distinguishable from opens done up top. (Ken Ray tells me that
* this is guaranteed to be synchronous, so we can compare thread IDs and
* figure out that a given open is from our driver, but this code is written
* assuming that we don't really need to distinguish.)
*
**********************************************************************/
#define __DEBUG_MODULE_IN_USE__ GCK_INTERNALPOLL_C
#include <wdm.h>
#include "Debug.h"
#include "GckShell.h"
DECLARE_MODULE_DEBUG_LEVEL((DBG_WARN|DBG_ERROR|DBG_CRITICAL));
/***********************************************************************************
**
** NTSTATUS GCK_IP_AddFileObject(IN PGCK_FILTER_EXT pFilterExt, IN PFILE_OBJECT pFileObject)
**
** @func Called to add a GCK_FILE_OPEN_ITEM entry corresponding to pFileObject to
** our list of file handles that we know about. Allocate and initializes the structure.
**
** @rdesc STATUS_SUCCESS, or STATUS_UNSUCCESSFUL if pFileObject is not found.
**
*************************************************************************************/
NTSTATUS
GCK_IP_AddFileObject
(
IN PGCK_FILTER_EXT pFilterExt,
IN PFILE_OBJECT pFileObject,
IN USHORT usDesiredShareAccess,
IN ULONG ulDesiredAccess
)
{
PGCK_FILE_OPEN_ITEM pNewFileOpenItem;
KIRQL OldIrql;
GCK_DBG_ENTRY_PRINT(("Entering GCK_IP_AddFileObject pFilterExt = 0x%0.8x, pFileObject = 0x%0.8x\n", pFilterExt, pFileObject));
//We need a spin lock to access this list
KeAcquireSpinLock(&pFilterExt->InternalPoll.InternalPollLock, &OldIrql);
//Check for sharing violation
if( !GCK_IP_CheckSharing(pFilterExt->InternalPoll.ShareStatus, usDesiredShareAccess, ulDesiredAccess) )
{
KeReleaseSpinLock(&pFilterExt->InternalPoll.InternalPollLock, OldIrql);
GCK_DBG_EXIT_PRINT(("Exiting GCK_IP_AddFileObject: Sharing Violation\n"));
return STATUS_SHARING_VIOLATION;
}
//Allocate Space for NewFileOpenItem;
pNewFileOpenItem = (PGCK_FILE_OPEN_ITEM)EX_ALLOCATE_POOL(NonPagedPool, sizeof(GCK_FILE_OPEN_ITEM));
if(!pNewFileOpenItem)
{
GCK_DBG_CRITICAL_PRINT(("Failed to allocate space for GCK_FILE_OPEN_ITEM\n"));
GCK_DBG_EXIT_PRINT(("Exiting GCK_IP_AddFileObject(1) STATUS_NO_MEMORY\n"));
return STATUS_NO_MEMORY;
}
//Initialize FileOpenItem
pNewFileOpenItem->fReadPending = FALSE;
pNewFileOpenItem->pFileObject = pFileObject;
pNewFileOpenItem->pNextOpenItem = NULL;
pNewFileOpenItem->ulAccess = ulDesiredAccess;
pNewFileOpenItem->usSharing = usDesiredShareAccess;
pNewFileOpenItem->fConfirmed = FALSE;
//Add New Item to head of list
pNewFileOpenItem->pNextOpenItem = pFilterExt->InternalPoll.pFirstOpenItem;
pFilterExt->InternalPoll.pFirstOpenItem = pNewFileOpenItem;
//Update SHARE_ACCESS
GCK_IP_AddSharing(&pFilterExt->InternalPoll.ShareStatus, usDesiredShareAccess, ulDesiredAccess);
//Release Spinlock
KeReleaseSpinLock(&pFilterExt->InternalPoll.InternalPollLock, OldIrql);
GCK_DBG_EXIT_PRINT(("Exiting GCK_IP_AddFileObject(2) STATUS_SUCCESS\n"));
return STATUS_SUCCESS;
}
/***********************************************************************************
**
** NTSTATUS GCK_IP_RemoveFileObject(IN PGCK_FILTER_EXT pFilterExt, IN PFILE_OBJECT pFileObject)
**
** @func Called to remove a GCK_FILE_OPEN_ITEM entry corresponding to pFileObject from
** our list of file handles that we know about. Deallocates structure.
**
** @rdesc STATUS_SUCCESS, or STATUS_UNSUCCESSFUL if pFileObject is not found.
**
*************************************************************************************/
NTSTATUS
GCK_IP_RemoveFileObject
(
IN PGCK_FILTER_EXT pFilterExt,
IN PFILE_OBJECT pFileObject
)
{
//Remove is just a negative confirmation
return GCK_IP_ConfirmFileObject(pFilterExt, pFileObject, FALSE);
}
NTSTATUS
GCK_IP_ConfirmFileObject
(
IN PGCK_FILTER_EXT pFilterExt,
IN PFILE_OBJECT pFileObject,
IN BOOLEAN fConfirm
)
{
//Find FileOpenItem and remove it.
PGCK_FILE_OPEN_ITEM pCurrentFileItem = pFilterExt->InternalPoll.pFirstOpenItem;
PGCK_FILE_OPEN_ITEM pPreviousFileItem = NULL;
GCK_DBG_ENTRY_PRINT(("Entering GCK_IP_ConfirmFileObject pFilterExt = 0x%0.8x, pFileObject = 0x%0.8x, fConfirm = %d\n", pFilterExt, pFileObject, fConfirm));
while(pCurrentFileItem)
{
//Check for File Object Match
if(pCurrentFileItem->pFileObject == pFileObject)
{
//If this is a confirmation, flag
if( fConfirm )
{
pCurrentFileItem->fConfirmed = TRUE;
}
//Otherwise, it is a negative confirmation, and we must remove it
else
{
//Remove from list
if( NULL == pPreviousFileItem)
{
pFilterExt->InternalPoll.pFirstOpenItem = pCurrentFileItem->pNextOpenItem;
}
else
{
pPreviousFileItem->pNextOpenItem = pCurrentFileItem->pNextOpenItem;
}
//Decrement number of open file objects
GCK_IP_RemoveSharing(&pFilterExt->InternalPoll.ShareStatus, pCurrentFileItem->usSharing, pCurrentFileItem->ulAccess);
//Free memory allocate for FileOpenItem
ExFreePool(pCurrentFileItem);
}
//Return Successfully
GCK_DBG_EXIT_PRINT(("Exiting GCK_IP_RemoveFileObject(1) STATUS_SUCCESS\n"));
return STATUS_SUCCESS;
}
pPreviousFileItem = pCurrentFileItem;
pCurrentFileItem = pCurrentFileItem->pNextOpenItem;
}
//If we are here the file object is not in our list. Either it was never added
//or is was removed
ASSERT(FALSE);
GCK_DBG_EXIT_PRINT(("Exiting GCK_IP_ConfirmFileObject(2) STATUS_UNSUCCESSFUL\n"));
return STATUS_UNSUCCESSFUL;
}
BOOLEAN
GCK_IP_CheckSharing
(
IN SHARE_STATUS ShareStatus,
IN USHORT usDesiredShareAccess,
IN ULONG ulDesiredAccess
)
{
//Check that no-one has exclusive access to the desire access
if(
( (ulDesiredAccess & FILE_WRITE_DATA) && (ShareStatus.SharedWrite < ShareStatus.OpenCount) ) ||
( (ulDesiredAccess & FILE_READ_DATA) && (ShareStatus.SharedRead < ShareStatus.OpenCount) )
)
{
return FALSE;
}
//Check that not requesting exclusive access, if already open
if(
( !(usDesiredShareAccess & FILE_SHARE_READ) && ShareStatus.Readers) ||
( !(usDesiredShareAccess & FILE_SHARE_WRITE) && ShareStatus.Writers) ||
(!usDesiredShareAccess && ShareStatus.OpenCount)
)
{
return FALSE;
}
//This would be approved
return TRUE;
}
BOOLEAN
GCK_IP_AddSharing
(
IN OUT SHARE_STATUS *pShareStatus,
IN USHORT usDesiredShareAccess,
IN ULONG ulDesiredAccess
)
{
//We assume this was checked before requested
ASSERT(GCK_IP_CheckSharing(*pShareStatus, usDesiredShareAccess, ulDesiredAccess));
pShareStatus->OpenCount++;
if(usDesiredShareAccess & FILE_SHARE_READ) pShareStatus->SharedRead++;
if(usDesiredShareAccess & FILE_SHARE_WRITE) pShareStatus->SharedWrite++;
if(ulDesiredAccess & FILE_WRITE_DATA) pShareStatus->Writers++;
if(ulDesiredAccess & FILE_READ_DATA) pShareStatus->Readers++;
return TRUE;
}
BOOLEAN
GCK_IP_RemoveSharing
(
IN OUT SHARE_STATUS *pShareStatus,
IN USHORT usDesiredShareAccess,
IN ULONG ulDesiredAccess
)
{
pShareStatus->OpenCount--;
if(usDesiredShareAccess & FILE_SHARE_READ) pShareStatus->SharedRead--;
if(usDesiredShareAccess & FILE_SHARE_WRITE) pShareStatus->SharedWrite--;
if(ulDesiredAccess & FILE_WRITE_DATA) pShareStatus->Writers--;
if(ulDesiredAccess & FILE_READ_DATA) pShareStatus->Readers--;
return TRUE;
}
typedef struct _GCK_INTERNEL_WorkItemExtension
{
WORK_QUEUE_ITEM WorkItem;
PGCK_FILTER_EXT pFilterExt;
} GCK_INTERNEL_WorkItemExtension;
VOID GCK_IP_WorkItem
(
IN PVOID pvContext
)
{
GCK_INTERNEL_WorkItemExtension* pWIExtension = (GCK_INTERNEL_WorkItemExtension*)pvContext;
if (pWIExtension != NULL)
{
GCKF_IncomingReadRequests(pWIExtension->pFilterExt, NULL);
ExFreePool(pWIExtension);
}
}
/***********************************************************************************
**
** NTSTATUS GCK_IP_OneTimePoll(IN PGCK_FILTER_EXT pFilterExt)
**
** @func If a private poll is not pending, it forces one.
**
** @rdesc STATUS_SUCCESS, or various errors
**
*************************************************************************************/
NTSTATUS
GCK_IP_OneTimePoll
(
IN PGCK_FILTER_EXT pFilterExt
)
{
PIO_STACK_LOCATION pPrivateIrpStack;
GCK_INTERNEL_WorkItemExtension* pWIExtension;
//
// Create a polling FileObject if necessary
//
if(!pFilterExt->InternalPoll.fReady)
{
NTSTATUS NtStatus;
if(GCK_STATE_STARTED == pFilterExt->eDeviceState)
{
pFilterExt->InternalPoll.InternalCreateThread=KeGetCurrentThread();
NtStatus = GCK_IP_CreateFileObject( &pFilterExt->InternalPoll.pInternalFileObject, pFilterExt->pPDO);
pFilterExt->InternalPoll.InternalCreateThread=NULL;
if( NT_SUCCESS(NtStatus) )
{
pFilterExt->InternalPoll.fReady = TRUE;
}
else
{
return STATUS_DEVICE_NOT_CONNECTED;
}
}
else
{
return STATUS_DEVICE_NOT_CONNECTED;
}
}
// If an read IRP is not pending, post one
/* if( pFilterExt->InternalPoll.fReadPending )
{
//If an IRP is pending, we're done
return STATUS_SUCCESS;
}
// Mark a read pending
pFilterExt->InternalPoll.fReadPending = TRUE;
*/ if (InterlockedExchange(&pFilterExt->InternalPoll.fReadPending, TRUE) == TRUE)
{
return STATUS_SUCCESS;
}
//Otherwise Post an IRP
GCK_DBG_RT_WARN_PRINT(("No IRP Pending, posting one.\n"));
// Give a change for the LEDs to update (we fake an incoming request)
pWIExtension = (GCK_INTERNEL_WorkItemExtension*)(EX_ALLOCATE_POOL(NonPagedPool, sizeof(GCK_INTERNEL_WorkItemExtension)));
if (pWIExtension != NULL)
{
pWIExtension->pFilterExt = pFilterExt;
ExInitializeWorkItem(&pWIExtension->WorkItem, GCK_IP_WorkItem, (void*)(pWIExtension));
// Need to callback at IRQL PASSIVE_LEVEL
ExQueueWorkItem(&pWIExtension->WorkItem, DelayedWorkQueue);
pWIExtension = NULL; // Will be deleted by the work item routine
}
//Setup the file object for out internal IRP
GCK_DBG_RT_WARN_PRINT(("Copying File object.\n"));
pPrivateIrpStack = IoGetNextIrpStackLocation(pFilterExt->InternalPoll.pPrivateIrp);
pPrivateIrpStack->FileObject = pFilterExt->InternalPoll.pInternalFileObject;
// Reset status
pFilterExt->InternalPoll.pPrivateIrp->IoStatus.Information = 0;
pFilterExt->InternalPoll.pPrivateIrp->IoStatus.Status = STATUS_SUCCESS;
// Reset the ByteOffset, Length
pPrivateIrpStack->Parameters.Read.ByteOffset.QuadPart = 0;
pPrivateIrpStack->Parameters.Read.Key = 0;
pPrivateIrpStack->Parameters.Read.Length =
(ULONG)pFilterExt->HidInfo.HidPCaps.InputReportByteLength;
// Set Completion routine to process poll after it is complete.
GCK_DBG_RT_WARN_PRINT(("Setting completion routine.\n"));
ASSERT(pFilterExt->InternalPoll.pPrivateIrp);
IoSetCompletionRoutine(
pFilterExt->InternalPoll.pPrivateIrp,
GCK_IP_ReadComplete,
(PVOID)pFilterExt,
TRUE,
TRUE,
TRUE
);
// We are about to generate another IRP so increment outstanding IO count
GCK_IncRemoveLock(&pFilterExt->RemoveLock);
// Send IRP down to driver
GCK_DBG_RT_WARN_PRINT(("Calling down to next driver.\n"));
return IoCallDriver (pFilterExt->pTopOfStack, pFilterExt->InternalPoll.pPrivateIrp);
}
/***********************************************************************************
**
** NTSTATUS GCK_IP_FullTimePoll(IN PGCK_FILTER_EXT pFilterExt, IN BOOLEAN fStart)
**
** @func Turns FullTime internal polling on or off. Actually changes a refcount.
** When the refcount goes to zero, polling is off, otherwise it is on. Calls
** GCK_IP_OneTimePoll which may be necessary to get ball rolling.
**
** @rdesc STATUS_SUCCESS, or various errors
**
*************************************************************************************/
NTSTATUS
GCK_IP_FullTimePoll
(
IN PGCK_FILTER_EXT pFilterExt,
IN BOOLEAN fStart
)
{
//Change number of requests for continuous background polling.
if(fStart)
{
pFilterExt->InternalPoll.ulInternalPollRef++;
ASSERT( 0!= pFilterExt->InternalPoll.ulInternalPollRef);
//There is no thread, the completion routine recycles the IRP
//and polls again if pFilterExt->InternalPoll.ulInternalPollRef > 0
//we need to hit GCK_IP_OneTimePoll just to get the ball rolling though.
if(GCK_STATE_STARTED == pFilterExt->eDeviceState )
{
return GCK_IP_OneTimePoll(pFilterExt);
}
return STATUS_SUCCESS;
}
//We need to decrment the refcount.
ASSERT( 0 != pFilterExt->InternalPoll.ulInternalPollRef);
if(0 != pFilterExt->InternalPoll.ulInternalPollRef)
{
pFilterExt->InternalPoll.ulInternalPollRef--;
}
return STATUS_SUCCESS;
}
/***********************************************************************************
**
** NTSTATUS GCK_IP_ReadComplete (IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID pContext)
**
** @func When a Private IRP is completed handles processing the data. Also
** important is that it repolls internall if pFilterExt->InternalPoll.ulInternalPollRef
** is greater than zero.
**
** @rdesc STATUS_SUCCESS, or various errors
**
*************************************************************************************/
NTSTATUS
GCK_IP_ReadComplete (
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN PVOID pContext
)
{
PGCK_FILTER_EXT pFilterExt;
PVOID pvReportBuffer;
UNREFERENCED_PARAMETER(pDeviceObject);
GCK_DBG_RT_ENTRY_PRINT(("Entering GCK_ReadComplete. pDO = 0x%0.8x, pIrp = 0x%0.8x, pContext = 0x%0.8x\n", pDeviceObject, pIrp, pContext));
// Cast context to device extension
pFilterExt = (PGCK_FILTER_EXT) pContext;
// Just an extra sanity check
ASSERT( GCK_DO_TYPE_FILTER == pFilterExt->ulGckDevObjType);
// Get Pointer to data
ASSERT(pIrp);
pvReportBuffer = GCK_GetSystemAddressForMdlSafe(pIrp->MdlAddress);
if(pvReportBuffer)
{
// Tell filter we have new data
GCKF_IncomingInputReports(pFilterExt, pvReportBuffer, pIrp->IoStatus);
}
//**
//** At this point we are done with the IRP
//** Need not complete it, it will be recycled.
//**
// Decrement outstanding IRP count
GCK_DecRemoveLock(&pFilterExt->RemoveLock);
// Read is no longer pending
pFilterExt->InternalPoll.fReadPending = FALSE;
//If the InternalPollRef is greater than zero,
//we need to be polling ourselves continuously
//but don't carry on if some catestrophic failure
//occured which lead to a MDL mapping failure
if( pvReportBuffer
&& (pFilterExt->InternalPoll.ulInternalPollRef) )
{
GCK_IP_OneTimePoll(pFilterExt);
}
//We don't want any cleanup to happen
return STATUS_MORE_PROCESSING_REQUIRED;
}
void GCK_IP_AddDevice(PGCK_FILTER_EXT pFilterExt)
{
KeInitializeSpinLock(&pFilterExt->InternalPoll.InternalPollLock);
pFilterExt->InternalPoll.ShareStatus.OpenCount = 0;
pFilterExt->InternalPoll.ShareStatus.Readers = 0;
pFilterExt->InternalPoll.ShareStatus.Writers = 0;
pFilterExt->InternalPoll.ShareStatus.SharedRead = 0;
pFilterExt->InternalPoll.ShareStatus.SharedWrite = 0;
pFilterExt->InternalPoll.fReadPending = FALSE;
pFilterExt->InternalPoll.ulInternalPollRef = 0;
pFilterExt->InternalPoll.pFirstOpenItem = NULL;
pFilterExt->InternalPoll.fReady = FALSE;
}
/***********************************************************************************
**
** NTSTATUS GCK_IP_Init (IN OUT PGCK_FILTER_EXT pFilterExt);
**
** @func As part of the initialization that occurs at the end of Start device on
** a filtered device, the filter must be prepared for internal polling.
** All data polling is internal. (IRP_MJ_READ are sent down directly once
** so that hidclass.sys can perform its security check, but the data from
** that poll is discarded.) Initialize InternalPoll Data in Device Extension
** including creating a pInternalFileObject, a pPrivateIRP and an associtated
** Buffer.
**
** @rdesc STATUS_SUCCESS, or various errors
**
*************************************************************************************/
NTSTATUS
GCK_IP_Init
(
IN OUT PGCK_FILTER_EXT pFilterExt
)
{
//NTSTATUS NtStatus;
LARGE_INTEGER lgiBufferOffset;
//Initialize the Internal Poll Structure
pFilterExt->InternalPoll.pInternalFileObject = NULL;
pFilterExt->InternalPoll.pPrivateIrp = NULL;
pFilterExt->InternalPoll.pucReportBuffer = NULL;
// Allocate a Buffer for the private IRP_MJ_READ
pFilterExt->InternalPoll.pucReportBuffer = (PUCHAR) EX_ALLOCATE_POOL
( NonPagedPool,
pFilterExt->HidInfo.HidPCaps.InputReportByteLength );
if(!pFilterExt->InternalPoll.pucReportBuffer)
{
GCK_DBG_CRITICAL_PRINT(("Failed to allocate Report Buffer for private IRPs\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
// Allocate private recyclable IRPs for internal polling
lgiBufferOffset.QuadPart = 0;
pFilterExt->InternalPoll.pPrivateIrp = IoBuildAsynchronousFsdRequest
(
IRP_MJ_READ,
pFilterExt->pTopOfStack,
pFilterExt->InternalPoll.pucReportBuffer,
(ULONG)pFilterExt->HidInfo.HidPCaps.InputReportByteLength,
&lgiBufferOffset,
NULL
);
if(!pFilterExt->InternalPoll.pPrivateIrp)
{
GCK_DBG_CRITICAL_PRINT(("Failed to allocate private Ping-Pong IRP\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
// Initialize status for very first IRP
pFilterExt->ioLastReportStatus.Information = (ULONG)pFilterExt->HidInfo.HidPCaps.InputReportByteLength;
pFilterExt->ioLastReportStatus.Status = STATUS_SUCCESS;
/**
** Cannot do this here since build 2006 or so,
** so defer until the first time we need it.
**
**
** //Open ourselves with a file object
** pFilterExt->InternalPoll.InternalCreateThread=KeGetCurrentThread();
** NtStatus = GCK_IP_CreateFileObject( &pFilterExt->InternalPoll.pInternalFileObject, pFilterExt->pTopOfStack);
** pFilterExt->InternalPoll.InternalCreateThread=NULL;
** if( NT_SUCCESS(NtStatus) )
** {
** pFilterExt->InternalPoll.fReady = TRUE;
** }
**/
return STATUS_SUCCESS;
}
/***********************************************************************************
**
** NTSTATUS GCK_IP_Cleanup (IN OUT PGCK_FILTER_EXT pFilterExt);
**
** @func Reverses Init, cancels outstanding internal polls, release pFileObject for
** internal polls, release private IRP and buffer. Does not release open file handles
**
** @rdesc STATUS_SUCCESS, STATUS_UNSUCCESSFUL if we could not cancel a pending poll
**
*************************************************************************************/
NTSTATUS
GCK_IP_Cleanup
(
IN OUT PGCK_FILTER_EXT pFilterExt
)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
if( pFilterExt->InternalPoll.fReady)
{
NtStatus = GCK_IP_CloseFileObject(pFilterExt);
}
if(NT_SUCCESS(NtStatus))
{
//Cleanup private IRP - and buffer, safely they may never had been allocated
if(pFilterExt->InternalPoll.pPrivateIrp)
{
IoFreeIrp(pFilterExt->InternalPoll.pPrivateIrp);
pFilterExt->InternalPoll.pPrivateIrp = NULL;
}
if(pFilterExt->InternalPoll.pucReportBuffer)
{
ExFreePool(pFilterExt->InternalPoll.pucReportBuffer);
pFilterExt->InternalPoll.pucReportBuffer = NULL;
}
}
return NtStatus;
}
/***********************************************************************************
**
** NTSTATUS GCK_IP_CreateFileObject (OUT PFILE_OBJECT *ppFileObject, IN PDEVICE_OBJECT pPDO);
**
** @func Calls IoGetDeviceObjectPointer, even though we already attached to the
** and have a pointer to the device object, the caller wants to create a
** new file object for internal calls down the stack that may require one.
**
** @rdesc STATUS_SUCCESS, or various errors
**
*************************************************************************************/
NTSTATUS
GCK_IP_CreateFileObject
(
OUT PFILE_OBJECT *ppFileObject,
IN PDEVICE_OBJECT pPDO
)
{
NTSTATUS NtStatus;
ULONG ulBufferLength = 0;
PVOID pPDONameBuffer = NULL;
UNICODE_STRING uniPDOName;
PDEVICE_OBJECT pDeviceObject;
//Get the size required for the PDO Name Buffer
NtStatus = IoGetDeviceProperty(
pPDO,
DevicePropertyPhysicalDeviceObjectName,
ulBufferLength,
pPDONameBuffer,
&ulBufferLength
);
ASSERT(STATUS_BUFFER_TOO_SMALL==NtStatus);
//Allocate space
pPDONameBuffer = EX_ALLOCATE_POOL(NonPagedPool, ulBufferLength);
if(!pPDONameBuffer)
{
return STATUS_NO_MEMORY;
}
//Get PDO Name
NtStatus = IoGetDeviceProperty(
pPDO,
DevicePropertyPhysicalDeviceObjectName,
ulBufferLength,
pPDONameBuffer,
&ulBufferLength
);
ASSERT(NT_SUCCESS(NtStatus));
if( NT_ERROR(NtStatus) )
{
return NtStatus;
}
//Make PDO Name into UNICODE string
RtlInitUnicodeString(&uniPDOName, pPDONameBuffer);
//Call IoGetDeviceObjectPointer to create a FILE_OBJECT
NtStatus = IoGetDeviceObjectPointer(
&uniPDOName,
FILE_READ_DATA,
ppFileObject,
&pDeviceObject
);
ASSERT(NT_SUCCESS(NtStatus));
//Release the space for Name
ExFreePool(pPDONameBuffer);
return NtStatus;
}
/***********************************************************************************
**
** NTSTATUS GCK_IP_CloseFileObject (OUT PFILE_OBJECT *ppFileObject, IN PDEVICE_OBJECT pPDO);
**
** @func Stops outstanding IO to hidclass.sys and closes handle
** @rdesc STATUS_SUCCESS, or STATUS_UNSUCCESSFUL
**
*************************************************************************************/
NTSTATUS
GCK_IP_CloseFileObject
(
IN OUT PGCK_FILTER_EXT pFilterExt
)
{
NTSTATUS NtStatus;
BOOLEAN fResult = TRUE;
//Turn off internal polling
pFilterExt->InternalPoll.fReady = FALSE;
//Cancel pending internal polls
if(pFilterExt->InternalPoll.fReadPending)
{
ASSERT(pFilterExt->InternalPoll.pPrivateIrp);
fResult = IoCancelIrp(pFilterExt->InternalPoll.pPrivateIrp);
}
if(!fResult)
{
return STATUS_UNSUCCESSFUL;
}
//***
//***If we are here, there are no pending polls, and there shall be no pending polls.
//***
//Release internal file object - if it had been created successfully
if(pFilterExt->InternalPoll.pInternalFileObject)
{
ObDereferenceObject((PVOID)pFilterExt->InternalPoll.pInternalFileObject);
pFilterExt->InternalPoll.pInternalFileObject=NULL;
}
return STATUS_SUCCESS;
}