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.
 
 
 
 
 
 

744 lines
25 KiB

// @doc
/**********************************************************************
*
* @module SWVBENUM.cpp |
*
* SideWinder Virtual Bus Enumerator
*
* History
* ----------------------------------------------------------
* Mitchell S. Dernis Original
*
* (c) 1986-1998 Microsoft Corporation. All right reserved.
* @index SideWinder Virtual Bus | SWVBENUM
*
* @topic SWVBENUM |
* This module implements the SideWinder Virtual Bus.
* The bus is nothing more than attaching this code on top of
* a FilterDO of a raw HID PDO, for the purpose of adding DevNodes
* for a virtual keyboard, virtual mouse, and the future virtual
* mixed devices. All of these devices are expected to be HID
* devices.<nl>
*
* The function driver for these devices the SWVBHID.sys (SideWinder
* Virtual Bus - HID). This driver is a HID mini-driver, however
* all IRPs are simply passed down to their PDO's, i.e. this
* code.<nl>
*
* The code in this module is independent of the functionality
* of the virtual devices. Basically all Power and PnP IRPs
* are handled here. All IRP_MJ_READ, IRP_MJ_WRITE,
* IRP_MJ_INTERNAL_IOCTL, and IRP_MJ_IOCTL entries are delegated
* via service table provided in the expose call to this module
* and stored in the device extension to a code module
* in this driver representing the device.<nl>
*
**********************************************************************/
#define __DEBUG_MODULE_IN_USE__ GCK_SWVBENUM_C
extern "C"
{
#include <WDM.H>
#include "GckShell.h"
#include "debug.h"
#include <stdio.h>
DECLARE_MODULE_DEBUG_LEVEL((DBG_WARN|DBG_ERROR|DBG_CRITICAL));
//DECLARE_MODULE_DEBUG_LEVEL((DBG_ALL));
}
#include "SWVBENUM.h"
//
// Mark the pageable routines as such
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, GCK_SWVB_DriverEntry)
#endif
// @globalv Globals for SWVB module
SWVB_GLOBALS SwvbGlobals;
/***********************************************************************************
**
** NTSTATUS GCK_SWVB_DriverEntry
**
** @func Initializes SWVB module. In particular the globals.
**
** @rdesc Returns STATUS_SUCCESS always.
**
** @comm Called by DriverEntry of main filter.
**
*************************************************************************************/
NTSTATUS
GCK_SWVB_DriverEntry
(
IN PDRIVER_OBJECT pDriverObject, // @parm DriverObject for module
IN PUNICODE_STRING puniRegistryPath // @parm Registry Path
)
{
GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_DriverEntry\n"));
UNREFERENCED_PARAMETER(pDriverObject);
UNREFERENCED_PARAMETER(puniRegistryPath);
SwvbGlobals.pBusFdo=NULL;
SwvbGlobals.pBusPdo=NULL;
SwvbGlobals.pDeviceRelations=NULL;
SwvbGlobals.ulDeviceRelationsAllocCount=0;
SwvbGlobals.ulDeviceNumber=0;
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_DriverEntry\n"));
return STATUS_SUCCESS;
}
VOID
GCK_SWVB_UnLoad()
{
if(SwvbGlobals.pDeviceRelations)
{
ExFreePool(SwvbGlobals.pDeviceRelations);
SwvbGlobals.pDeviceRelations = NULL;
}
}
/***********************************************************************************
**
** NTSTATUS GCK_SWVB_SetBusDOs
**
** @func Sets the Device Object (PDO and FDO), to use as the base of the
** SideWinder Virtual Bus.
**
** @rdesc S_OK on success
**
** @comm A real device is needed on the system in order to
** support the virtual device. When the first such device is detected,
** this function is called to set the filter device object of that
** device to be the Fdo of the SWVB, and its Pdo to be the Pdo of the bus.
** If that device object is removed, this function can be called to move
** the SWVB unto another physical device, or it can be called with NULL
** for both arguments to remove the SWVB.
**
*************************************************************************************/
NTSTATUS
GCK_SWVB_SetBusDOs
(
IN PDEVICE_OBJECT pBusFdo, // @parm [in] Pointer to Fdo (Filter Device Object - actually)
IN PDEVICE_OBJECT pBusPdo // @parm [in] Pointer to Pdo
)
{
PDEVICE_OBJECT pOldBusFdo;
PDEVICE_OBJECT pOldBusPdo;
GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_SetBusDOs\n"));
// Save old Bus DO info
pOldBusFdo = SwvbGlobals.pBusFdo;
pOldBusPdo = SwvbGlobals.pBusPdo;
// Update Bus DO info
SwvbGlobals.pBusFdo = pBusFdo;
SwvbGlobals.pBusPdo = pBusPdo;
// Invalidate the old and the new pBusPdo's - iff
// (they exist && there is at least one device on the bus)
// This will fire up the PnP system and cause it to re-detect
// everything.
if(SwvbGlobals.pDeviceRelations && SwvbGlobals.pDeviceRelations->Count)
{
if(pOldBusPdo)
{
IoInvalidateDeviceRelations(pOldBusPdo, BusRelations);
}
if(SwvbGlobals.pBusPdo)
{
IoInvalidateDeviceRelations(SwvbGlobals.pBusPdo, BusRelations);
}
}
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_SetBusDOs\n"));
return STATUS_SUCCESS;
}
/***********************************************************************************
**
** NTSTATUS GCK_SWVB_HandleBusRelations
**
** @func Handles queries for the BusRelations on behalf of the filter device object,
** which the SWVB is sitting on. Basically all we need do is copy over
** over our device relations, being cognizant that someone may layer on top
** of us and possibly has added stuff already.
** @rdesc Same as in the IoStatus and appropriate to return.
**
*************************************************************************************/
NTSTATUS
GCK_SWVB_HandleBusRelations
(
IN OUT PIO_STATUS_BLOCK pIoStatus // @parm [out] IoStatus block is filled out by this routine.
)
{
ULONG ulTotalCount;
PDEVICE_RELATIONS pExistingRelations;
PDEVICE_RELATIONS pDeviceRelations;
GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_HandleBusRelations. pIoStatus = 0x%0.8x\n", pIoStatus));
// Copy the count of what we know about
ulTotalCount = SwvbGlobals.pDeviceRelations->Count;
GCK_DBG_TRACE_PRINT(("We have %d PDOs\n", ulTotalCount));
// Read existing relations
pExistingRelations = (PDEVICE_RELATIONS)pIoStatus->Information;
// Add the count that someone on top of us may have added.
if( NULL != pExistingRelations)
{
GCK_DBG_TRACE_PRINT(("There were %d existing bus relations.\n", pExistingRelations->Count));
ulTotalCount += pExistingRelations->Count;
}
// Allocate new relations structure
pDeviceRelations = (PDEVICE_RELATIONS)EX_ALLOCATE_POOL(NonPagedPool, (sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (ulTotalCount-1)) );
// Abort if allocation failed
if(!pDeviceRelations)
{
pIoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_BusRelations(1): STATUS_INSUFFICIENT_RESOURCES\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
pDeviceRelations->Count = 0;
// Copy pExistingRelations (from above us perhaps) if there are any.
if( pExistingRelations )
{
for( pDeviceRelations->Count = 0; pDeviceRelations->Count < pExistingRelations->Count; pDeviceRelations->Count++)
{
GCK_DBG_TRACE_PRINT(("Exiting relation (PDO = 0x%0.8x)\n", pExistingRelations->Objects[pDeviceRelations->Count]));
pDeviceRelations->Objects[pDeviceRelations->Count] = pExistingRelations->Objects[pDeviceRelations->Count];
}
ExFreePool(pExistingRelations);
}
// Add the relations that we know about
if(SwvbGlobals.pDeviceRelations)
{
ULONG ulIndex;
for(ulIndex=0; ulIndex < SwvbGlobals.pDeviceRelations->Count; ulIndex++, pDeviceRelations->Count++)
{
GCK_DBG_TRACE_PRINT(("Our relation (PDO = 0x%0.8x)\n", SwvbGlobals.pDeviceRelations->Objects[ulIndex]));
pDeviceRelations->Objects[pDeviceRelations->Count] = SwvbGlobals.pDeviceRelations->Objects[ulIndex];
// Reference these guys as you add them
ObReferenceObject(pDeviceRelations->Objects[pDeviceRelations->Count]);
}
//minor sanity check
ASSERT(pDeviceRelations->Count == ulTotalCount);
}
// Fill out the IoStatus block
pIoStatus->Information = (ULONG)pDeviceRelations;
pIoStatus->Status = STATUS_SUCCESS;
//Get outta here
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_BusRelations(2): STATUS_SUCCESS\n"));
return STATUS_SUCCESS;
}
/***********************************************************************************
**
** NTSTATUS GCK_SWVB_Expose
**
** @func Exposes a new virtual device
**
** @rdesc STATUS_SUCCESS on success, various errors
**
** @comm Expose is called to add a new virtual device to the system.<nl>
** The new device object is not returned, rather the InitDevice function
** passed in pSwvbExposeData is called when it is time to initialize the
** new device, the caller also must cache the device during that call
** so that it can remove it later.
**
** @xref SWVB_EXPOSE_DATA
*************************************************************************************/
NTSTATUS
GCK_SWVB_Expose
(
IN PSWVB_EXPOSE_DATA pSwvbExposeData // @parm all the data needed to expose a PDO
)
{
NTSTATUS NtStatus;
UNICODE_STRING uniPdoNameString;
PWCHAR pcwPdoName;
PDEVICE_OBJECT pVdPdo;
PSWVB_PDO_EXT pSwvbPdoExt;
ULONG ulTotalExtensionSize;
ULONG ulHardwareIDLength;
PAGED_CODE();
GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Expose. pSwvbExposeData = 0x%0.8x\n", pSwvbExposeData));
//Calculate the needed extension size
ulTotalExtensionSize = sizeof(SWVB_PDO_EXT) + pSwvbExposeData->ulDeviceExtensionSize;
// Create a name for the Pdo
pcwPdoName = (PWCHAR)EX_ALLOCATE_POOL(PagedPool, sizeof(SWVB_DEVICE_NAME_BASE));
if( !pcwPdoName )
{
GCK_DBG_ERROR_PRINT(("Exiting GCK_SWVB_Expose(1) ERROR:Failed to allocate PDO Name\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
swprintf(pcwPdoName, SWVB_DEVICE_NAME_TMPLT, SwvbGlobals.ulDeviceNumber++);
RtlInitUnicodeString(&uniPdoNameString, pcwPdoName);
// Create the PDO
NtStatus = IoCreateDevice(
SwvbGlobals.pBusFdo->DriverObject,
ulTotalExtensionSize,
&uniPdoNameString,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&pVdPdo
);
//Done with the name
ExFreePool(pcwPdoName);
if( !NT_SUCCESS(NtStatus) )
{
GCK_DBG_ERROR_PRINT(("Exiting GCK_SWVB_Expose(2) ERROR:Failed to Create PDO, NtStatus = 0x%0.8x\n", NtStatus));
return NtStatus;
}
// Ensure that we will be able to remember this new Pdo.
if(!SwvbGlobals.pDeviceRelations)
{
//
// Three PDO's is pretty cheap and will suffice most of the time, avoiding reallocation.
// We hard code this here, as this is not really a parameter that you need to change.
// If we run over 3 than it will reallocate as needed anyway. - The device relations
// already as room for 1 device object so we just need to add the size of 2 pointers
// to get to three.
//
ULONG ulSize = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT)*2;
SwvbGlobals.pDeviceRelations = (PDEVICE_RELATIONS)EX_ALLOCATE_POOL(NonPagedPool, ulSize);
if(!SwvbGlobals.pDeviceRelations)
{
IoDeleteDevice(pVdPdo); //guess we won't be needing this afterall
GCK_DBG_ERROR_PRINT(("Exiting GCK_SWVB_Expose(3): Failed to allocate SwvbGlobals.pDeviceRelations\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
SwvbGlobals.pDeviceRelations->Count = 0;
SwvbGlobals.ulDeviceRelationsAllocCount = 3; //we made space for three
}
// If the DEVICE_RELATIONS structure is not large enough, grow it.
if(SwvbGlobals.pDeviceRelations->Count == SwvbGlobals.ulDeviceRelationsAllocCount)
{
ULONG ulNewAllocCount;
ULONG ulNewAllocSize;
ULONG ulOldAllocSize;
PDEVICE_RELATIONS pTempDeviceRelations;
ulNewAllocCount = SwvbGlobals.ulDeviceRelationsAllocCount*2;
ulNewAllocSize = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT)*(ulNewAllocCount-1);
ulOldAllocSize = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT)*(SwvbGlobals.ulDeviceRelationsAllocCount-1);
pTempDeviceRelations = (PDEVICE_RELATIONS)EX_ALLOCATE_POOL(NonPagedPool, ulNewAllocSize);
//Make sure that allocation worked
if(!pTempDeviceRelations)
{
IoDeleteDevice(pVdPdo); //guess we won't be needing this afterall
GCK_DBG_ERROR_PRINT(("Exiting GCK_SWVB_Expose(4): Failed to grow SwvbGlobals.pDeviceRelations\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
//Copy all data
RtlCopyMemory(pTempDeviceRelations, SwvbGlobals.pDeviceRelations, ulOldAllocSize);
//Update info
SwvbGlobals.ulDeviceRelationsAllocCount = ulNewAllocCount;
SwvbGlobals.pDeviceRelations = pTempDeviceRelations;
/*
* BUGBUG: Memory Leak. After RC replace above line with the following
*
* PDEVICE_RELATIONS pTemp2 = SwvbGlobals.pDeviceRelations;
* SwvbGlobals.pDeviceRelations = pTempDeviceRelations;
* ExFreePool(pTemp2);
*
*/
}
// Reference the newly created pdo
ObReferenceObject(pVdPdo);
// Initialize the device extention
pSwvbPdoExt = (PSWVB_PDO_EXT)pVdPdo->DeviceExtension;
pSwvbPdoExt->ulGckDevObjType = GCK_DO_TYPE_SWVB;
pSwvbPdoExt->fAttached=TRUE;
pSwvbPdoExt->fStarted=FALSE;
pSwvbPdoExt->fRemoved = FALSE;
pSwvbPdoExt->pServiceTable = pSwvbExposeData->pServiceTable;
pSwvbPdoExt->ulInstanceNumber = pSwvbExposeData->ulInstanceNumber;
pSwvbPdoExt->ulOpenCount = 0;
GCK_InitRemoveLock(&pSwvbPdoExt->RemoveLock, "Virtual Device");
// Copy the HardwareID
ulHardwareIDLength = MultiSzWByteLength(pSwvbExposeData->pmwszDeviceId);
pSwvbPdoExt->pmwszHardwareID = (PWCHAR)EX_ALLOCATE_POOL( NonPagedPool, ulHardwareIDLength);
if(!pSwvbPdoExt->pmwszHardwareID)
{
ObDereferenceObject(pVdPdo);
IoDeleteDevice(pVdPdo); //guess we won't be needing this afterall
GCK_DBG_ERROR_PRINT(("Exiting GCK_SWVB_Expose(5): Failed to allocate space for HardwareId\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory( pSwvbPdoExt->pmwszHardwareID, pSwvbExposeData->pmwszDeviceId, ulHardwareIDLength);
//** CAVEAT From here to end of function must succeed! We
//** CAVEAT have no way of telling the virtual device
//** CAVEAT that afterall, we decided not to expose that PDO it
//** CAVEAT it has already initialized!
// Allow virtual device code to init its part of the extension
pSwvbExposeData->pfnInitDevice(pVdPdo, pSwvbExposeData->ulInitContext);
//mark end of initialization in the device object
pVdPdo->Flags |= (DO_DIRECT_IO | DO_POWER_PAGABLE);
pVdPdo->Flags &= ~DO_DEVICE_INITIALIZING;
//Sanity check of code a few steps ago.
ASSERT(SwvbGlobals.pDeviceRelations->Count < SwvbGlobals.ulDeviceRelationsAllocCount);
//Add our Pdo to the list
SwvbGlobals.pDeviceRelations->Objects[SwvbGlobals.pDeviceRelations->Count++] = pVdPdo;
//
// Invalidate Device Relations - will pique some interest in what we have done here
// Verify that we have a bus if not we are OK, when the bus is set everything will work,
// but we assert becuase we really want to force the client code to add the bus before the device.
//
ASSERT( SwvbGlobals.pBusFdo );
ASSERT( SwvbGlobals.pBusPdo );
if( SwvbGlobals.pBusFdo && SwvbGlobals.pBusPdo)
{
IoInvalidateDeviceRelations(SwvbGlobals.pBusPdo, BusRelations);
}
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_Expose(5): Success\n"));
return STATUS_SUCCESS;
}
/***********************************************************************************
**
** NTSTATUS GCK_SWVB_Remove
**
** @func Removes a virtual device from the system. Actually we just mark it
** for removal and tell PnP to reenumerate.
**
** @rdesc STATUS_SUCCESS on success, various errors
**
** @comm The Pdo should be one that was sent to pfnInitDevice when <f GCK_SWVB_Expose>
** was called.<nl>
**
*************************************************************************************/
NTSTATUS
GCK_SWVB_Remove
(
IN PDEVICE_OBJECT pPdo // @parm Pdo to remove
)
{
ULONG ulMatchIndex = 0xFFFFFFFF;
GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Remove: pPdo = 0x%0.8x\n", pPdo));
// Find and Remove Pdo from SwvbGlobals.pDeviceRelations
if(SwvbGlobals.pDeviceRelations)
{
ULONG ulIndex;
for(ulIndex = 0; ulIndex < SwvbGlobals.pDeviceRelations->Count; ulIndex++)
{
if(SwvbGlobals.pDeviceRelations->Objects[ulIndex] == pPdo)
{
ulMatchIndex = ulIndex;
break;
}
}
}
//if we found a match remove it from it
if(0xFFFFFFFF == ulMatchIndex)
{
//No one should ever try to remove a device that is not in the list
ASSERT(FALSE);
GCK_DBG_EXIT_PRINT(("Error GCK_SWVB_Remove: Attempt to remove non-existant device!\n"));
return STATUS_UNSUCCESSFUL;
}
//Copy last PDO over this one and dec count, works even if we are last
SwvbGlobals.pDeviceRelations->Objects[ulMatchIndex]
= SwvbGlobals.pDeviceRelations->Objects[--(SwvbGlobals.pDeviceRelations->Count)];
//
// Mark device as unattached so when PnP says to remove it, we
// do remove it and clean up everything, rather than hanging on
// to it and waiting for more querying IRPs
((PSWVB_PDO_EXT)pPdo->DeviceExtension)->fAttached =FALSE;
//
// If it has been removed already, we need to delete, because the PnP system already
// doesn't know about, and we just detattached, so once we leave this routine, we don't
// know about it. So Delete now, or it sticks to us. Then we go to remove ourselves
// we will notice that we still have some Device Objects in our pockets(pDriverObject device object list),
// and we will wonder where they came from, and what type they are? So delete them now!
//
if(TRUE == ((PSWVB_PDO_EXT)pPdo->DeviceExtension)->fRemoved)
{
PSWVB_PDO_EXT pPdoExt = (PSWVB_PDO_EXT)pPdo->DeviceExtension;
NTSTATUS NtStatus;
// Give virtual device a chance at the IRP
if(pPdoExt->pServiceTable->pfnRemove)
{
NtStatus = pPdoExt->pServiceTable->pfnRemove(pPdo, NULL);
}
// failure to succeed is pretty darn serious
if(!NT_SUCCESS(NtStatus))
{
ASSERT(FALSE);
GCK_DBG_CRITICAL_PRINT(("Virtual Device had the gall to fail remove!\n"));
}
// free memory for storing the HardwareID
ASSERT(pPdoExt->pmwszHardwareID);
ExFreePool(pPdoExt->pmwszHardwareID);
GCK_DBG_TRACE_PRINT(("Detattached device has already been removed by PnP, so clean it up.\n"));
if( 0 == ((PSWVB_PDO_EXT)pPdo->DeviceExtension)->ulOpenCount )
{
ObDereferenceObject(pPdo);
IoDeleteDevice(pPdo);
}
}
// Invalidate the BUS relations so that PnP will renumerate the bus.
// Of course since we rely on others, it is possible that we temporarily
// don't have a Bus, in which case we skip this step.
//
// If we don't have DO for the Bus we shouldn't lose any sleep on two accounts:
// 1. It is possible that all the real devices have been yanked from the system, in which case
// PnP will start removing everyone below the node that was yanked, starting at the bottom.
// That means virtual devices have been removed as far as PnP is concerned and our remove
// routine for those devices has been called. However, until all the underlying real devices
// get removed by PnP (which is later), they don't relealize it is time to tell us to get rid of the
// virtual devices. No big woop. We will delete the devices when they tell us. If the virtual
// device is shared among real devices (like a virtual keyboard), they will tell us when the last
// one is removed. This scenario is infact the normal way things happen when the last device is pulled,
// or when the system is powered down.
// 2. It is possible that the filter drivers have temporarily decided to pull our bus. In this case,
// everything will be fine and dandy when we get a new bus to sit on, as we will Invalidate Bus relations
// at that time.
if(SwvbGlobals.pBusPdo)
{
IoInvalidateDeviceRelations(SwvbGlobals.pBusPdo, BusRelations);
}
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_Remove: Success\n"));
return STATUS_SUCCESS;
}
/***********************************************************************************
**
** ULONG MultiSzWByteLength(PWCHAR pmwszBuffer);
**
** @func Calculates the length in bytes of a Wide Multi String,
** including terminating characters. Multi-sz is terminated by two NULLs
** in a row.
**
** @rdesc Size in characters, including terminating characters.
**
*************************************************************************************/
ULONG
MultiSzWByteLength
(
PWCHAR pmwszBuffer // @parm Pointer to UNICODE multi-string
)
{
PWCHAR pmwszStart = pmwszBuffer;
do
{
while(*pmwszBuffer++);
}while(*pmwszBuffer++);
return (ULONG)((PCHAR)pmwszBuffer -(PCHAR)pmwszStart);
}
/***********************************************************************************
**
** NTSTATUS GCK_SWVB_Create
**
** @func Handles IRP_MJ_CREATE for virtual devices.
** delegates using their service table.
**
** @rdesc STATUS_SUCCESS on success, various errors
**
** @todo Add basic checks to make sure device is valid before delegating
**
*************************************************************************************/
NTSTATUS
GCK_SWVB_Create
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
NTSTATUS NtStatus;
PSWVB_PDO_EXT pPdoExt;
GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Create\n"));
// Cast device extension
pPdoExt = (PSWVB_PDO_EXT) pDeviceObject->DeviceExtension;
// Just an extra sanity check
ASSERT(GCK_DO_TYPE_SWVB == pPdoExt->ulGckDevObjType);
//Delegate
NtStatus = pPdoExt->pServiceTable->pfnCreate(pDeviceObject, pIrp);
if( NT_SUCCESS(NtStatus) )
{
pPdoExt->ulOpenCount++;
}
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_Create, Status = 0x%0.8x\n", NtStatus));
return NtStatus;
}
/***********************************************************************************
**
** NTSTATUS GCK_SWVB_Close
**
** @func Handles IRP_MJ_CLOSE for virtual devices.
** delegates using their service table.
**
** @rdesc STATUS_SUCCESS on success, various errors
**
** @todo Add basic checks to make sure device is valid before delegating
**
*************************************************************************************/
NTSTATUS
GCK_SWVB_Close
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
NTSTATUS NtStatus;
PSWVB_PDO_EXT pPdoExt;
GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Close\n"));
// Cast device extension
pPdoExt = (PSWVB_PDO_EXT) pDeviceObject->DeviceExtension;
// Just an extra sanity check
ASSERT(GCK_DO_TYPE_SWVB == pPdoExt->ulGckDevObjType);
//Delegate
NtStatus = pPdoExt->pServiceTable->pfnClose(pDeviceObject, pIrp);
//if successfully closed, decrement count
if( NT_SUCCESS(NtStatus) )
{
if(0==--pPdoExt->ulOpenCount)
{
//if the device is removed, we need to delete it.
if(pPdoExt->fRemoved)
{
ObDereferenceObject(pDeviceObject);
IoDeleteDevice(pDeviceObject);
}
}
}
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_Close, Status = 0x%0.8x\n", NtStatus));
return NtStatus;
}
/***********************************************************************************
**
** NTSTATUS GCK_SWVB_Read
**
** @func Handles IRP_MJ_READ for virtual devices.
** delegates using their service table.
**
** @rdesc STATUS_SUCCESS on success, various errors
**
** @todo Add basic checks to make sure device is valid before delegating
**
*************************************************************************************/
NTSTATUS
GCK_SWVB_Read
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
NTSTATUS NtStatus;
PSWVB_PDO_EXT pPdoExt;
GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Reade\n"));
// Cast device extension
pPdoExt = (PSWVB_PDO_EXT) pDeviceObject->DeviceExtension;
// Just an extra sanity check
ASSERT(GCK_DO_TYPE_SWVB == pPdoExt->ulGckDevObjType);
//Delegate
NtStatus = pPdoExt->pServiceTable->pfnRead(pDeviceObject, pIrp);
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_Read, Status = 0x%0.8x\n", NtStatus));
return NtStatus;
}
/***********************************************************************************
**
** NTSTATUS GCK_SWVB_Ioctl
**
** @func Handles IRP_MJ_IOCTL and IRP_MJ_INTERNAL_IOCTL for virtual devices.
** delegates using their service table.
**
** @rdesc STATUS_SUCCESS on success, various errors
**
** @todo Add basic checks to make sure device is valid before delegating
**
*************************************************************************************/
NTSTATUS
GCK_SWVB_Ioctl
(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
NTSTATUS NtStatus;
PSWVB_PDO_EXT pPdoExt;
GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Ioctl\n"));
// Cast device extension
pPdoExt = (PSWVB_PDO_EXT) pDeviceObject->DeviceExtension;
// Just an extra sanity check
ASSERT(GCK_DO_TYPE_SWVB == pPdoExt->ulGckDevObjType);
//if device is stopped, complete here, less work for virtual devices
if(
(pPdoExt->fRemoved) ||
(!pPdoExt->fStarted)
)
{
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = STATUS_DELETE_PENDING;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_DELETE_PENDING;
}
//Delegate
NtStatus = pPdoExt->pServiceTable->pfnIoctl(pDeviceObject, pIrp);
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_Ioctl, Status = 0x%0.8x\n", NtStatus));
return NtStatus;
}