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.
 
 
 
 
 
 

483 lines
15 KiB

// @doc
/**********************************************************************
*
* @module SWVB_PnP.cpp |
*
* Power and PnP handlers for SWVB Virtual Devices
*
* History
* ----------------------------------------------------------
* Mitchell S. Dernis Original
*
* (c) 1986-1998 Microsoft Corporation. All right reserved.
*
* @topic SWVB_PnP |
* Power and PnP IRPs are handled here as if for a PDO
**********************************************************************/
#define __DEBUG_MODULE_IN_USE__ GCK_SWVB_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"
#include <stdio.h>
/***********************************************************************************
**
** NTSTATUS GCK_SWVB_PnP(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
**
** @func Handles IRP_MJ_PNP for Virtual Devices.
**
** @rdesc STATUS_SUCCESS, or various errors
**
*************************************************************************************/
NTSTATUS GCK_SWVB_PnP
(
IN PDEVICE_OBJECT pDeviceObject, // @parm Device Object for our context
IN PIRP pIrp // @parm IRP to handle
)
{
NTSTATUS NtStatus;
PIO_STACK_LOCATION pIrpStack;
PSWVB_PDO_EXT pPdoExt;
PDEVICE_CAPABILITIES pDeviceCapabilities;
PAGED_CODE ();
GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_PnP\n"));
//
// By default we will not change the status
//
NtStatus = pIrp->IoStatus.Status;
//
// PDO Device Extension
//
pPdoExt = (PSWVB_PDO_EXT) pDeviceObject->DeviceExtension;
ASSERT( GCK_DO_TYPE_SWVB == pPdoExt->ulGckDevObjType);
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
GCK_IncRemoveLock(&pPdoExt->RemoveLock);
//
// Handle by Minor IRP code
//
switch (pIrpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_START_DEVICE\n"));
pPdoExt->fStarted = TRUE;
pPdoExt->fRemoved = FALSE;
//Give virtual device a chance at the IRP
if(pPdoExt->pServiceTable->pfnStart)
{
NtStatus = pPdoExt->pServiceTable->pfnStart(pDeviceObject, pIrp);
}
else
{
NtStatus = STATUS_SUCCESS;
}
break;
case IRP_MN_STOP_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_STOP_DEVICE\n"));
pPdoExt->fStarted = FALSE;
//Give virtual device a chance at the IRP
if(pPdoExt->pServiceTable->pfnStop)
{
NtStatus = pPdoExt->pServiceTable->pfnStop(pDeviceObject, pIrp);
}
else
{
NtStatus = STATUS_SUCCESS;
}
break;
case IRP_MN_REMOVE_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_REMOVE_DEVICE\n"));
//We are not setup to handle remove twice.
if(pPdoExt->fRemoved)
{
pIrp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_PnP STATUS_NO_SUCH_DEVICE on remove\n"));
return STATUS_NO_SUCH_DEVICE;
}
//Sometimes we get a remove without a stop, so do the stop stuff if necessary
if(pPdoExt->fStarted)
{
pPdoExt->fStarted = FALSE;
//Give virtual device a chance at the IRP
if(pPdoExt->pServiceTable->pfnStop)
{
NtStatus = pPdoExt->pServiceTable->pfnStop(pDeviceObject, pIrp);
}
}
// We will no longer receive requests for this device as it has been removed.
pPdoExt->fRemoved = TRUE;
// Undo our increment upon entry to this routine
GCK_DecRemoveLock(&pPdoExt->RemoveLock);
//We may have ordered this removal, or the PnP system
//may just be rearranging things for us. If we ordered it,
//we need to cleanup, and give the virtual device a chance
//to cleanup. If the PnP system is rearranging things we nod
//back, sure it is removed, and pretty much ignore it.
if(!pPdoExt->fAttached)
{
// Give virtual device a chance at the IRP
if(pPdoExt->pServiceTable->pfnRemove)
{
NtStatus = pPdoExt->pServiceTable->pfnRemove(pDeviceObject, pIrp);
}
// 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"));
return NtStatus;
}
// free memory for storing the HardwareID
ASSERT(pPdoExt->pmwszHardwareID);
ExFreePool(pPdoExt->pmwszHardwareID);
//
// Undo the bias Irp count so it can go to zero
// if this does not take it to zero, we have to wait
// until it goes to zero, forever.
//
GCK_DecRemoveLockAndWait(&pPdoExt->RemoveLock, NULL);
// Delete this device, if the open count is zero
if( 0 == pPdoExt->ulOpenCount )
{
ObDereferenceObject(pDeviceObject);
IoDeleteDevice(pDeviceObject);
}
}
// Must succeed this
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_PnP succeeding remove\n"));
return STATUS_SUCCESS;
case IRP_MN_QUERY_DEVICE_RELATIONS:
GCK_DBG_TRACE_PRINT(("IRP_MN_QUERY_DEVICE_RELATIONS: Type = %d\n",
pIrpStack->Parameters.QueryDeviceRelations.Type));
// TargetDeviceRelation just wants to know who the PDO is, and it
// is us so we handle it.
if (TargetDeviceRelation == pIrpStack->Parameters.QueryDeviceRelations.Type)
{
PDEVICE_RELATIONS pDeviceRelations;
GCK_DBG_TRACE_PRINT(("TargetDeviceRelations\n"));
pDeviceRelations = (PDEVICE_RELATIONS) pIrp->IoStatus.Information;
if (!pDeviceRelations)
{
pDeviceRelations = (PDEVICE_RELATIONS)EX_ALLOCATE_POOL(PagedPool, sizeof(DEVICE_RELATIONS));
if (!pDeviceRelations) {
GCK_DBG_ERROR_PRINT(("Couldn' allocate DEVICE_RELATIONS for TargetDevice!!\n"));
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
}
else if (pDeviceRelations->Count != 0)
{
ULONG uIndex;
// Nobody but the PDO should be setting this value!
ASSERT(pDeviceRelations->Count == 0);
//
// Deref any objects that were previously in the list
// This code copied out of some system code (gameenum perhaps)
// Seems like this code should not be necessary, but what the
// hell? It does no harm.
for( uIndex= 0; uIndex< pDeviceRelations->Count; uIndex++)
{
ObDereferenceObject(pDeviceRelations->Objects[uIndex]);
pDeviceRelations->Objects[uIndex] = NULL;
}
}
pDeviceRelations->Count = 1;
pDeviceRelations->Objects[0] = pDeviceObject;
ObReferenceObject(pDeviceObject);
NtStatus = STATUS_SUCCESS;
pIrp->IoStatus.Information = (ULONG) pDeviceRelations;
break;
}
//
// Fall through
//
NtStatus = pIrp->IoStatus.Status;
break;
case IRP_MN_QUERY_CAPABILITIES:
GCK_DBG_TRACE_PRINT(("IRP_MN_QUERY_CAPABILITIES\n"));
// Get the packet.
pDeviceCapabilities=pIrpStack->Parameters.DeviceCapabilities.Capabilities;
// Set the capabilities.
pDeviceCapabilities->Version = 1;
pDeviceCapabilities->Size = sizeof (DEVICE_CAPABILITIES);
// BUG If we get a virtual keystroke it would be nice
// BUG to shut off the screen saver. Not sure if this
// BUG is related or not.
pDeviceCapabilities->SystemWake = PowerSystemUnspecified;
pDeviceCapabilities->DeviceWake = PowerDeviceUnspecified;
// We have no latencies
pDeviceCapabilities->D1Latency = 0;
pDeviceCapabilities->D2Latency = 0;
pDeviceCapabilities->D3Latency = 0;
// No locking or ejection
pDeviceCapabilities->LockSupported = FALSE;
pDeviceCapabilities->EjectSupported = FALSE;
// Device can be physically removed.
// Technically there is no physical device to remove, but this bus
// driver can yank the PDO from the PlugPlay system, whenever
// the last joystick goes away.
pDeviceCapabilities->Removable = TRUE;
pDeviceCapabilities->SurpriseRemovalOK = TRUE;
//This will force HIDSwvd.sys to be loaded
pDeviceCapabilities->RawDeviceOK = FALSE;
//Should surpress most UI
pDeviceCapabilities->SilentInstall = TRUE;
// not Docking device
pDeviceCapabilities->DockDevice = FALSE;
//We want to avoid having PnP attach some extra info.
//So impose that only one bus can be on the system at a time.
pDeviceCapabilities->UniqueID = TRUE;
NtStatus = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_ID:
GCK_DBG_TRACE_PRINT(("IRP_MN_QUERY_ID\n"));
//
// Handle by type of ID requested
//
switch (pIrpStack->Parameters.QueryId.IdType)
{
case BusQueryDeviceID:
// this can be the same as the hardware ids (which requires a multi
// sz) ... we are just allocating more than enough memory
case BusQueryHardwareIDs:
{
ULONG ulLength;
ULONG ulTotalLength;
PWCHAR pmwszBuffer;
// return a multi WCHAR (null terminated) string (null terminated)
// array for use in matching hardare ids in inf files;
ulLength = MultiSzWByteLength(pPdoExt->pmwszHardwareID);
ulTotalLength = ulLength + sizeof(SWVB_BUS_ID);
pmwszBuffer = (PWCHAR)EX_ALLOCATE_POOL(PagedPool, ulTotalLength);
if (pmwszBuffer)
{
RtlCopyMemory (pmwszBuffer, SWVB_BUS_ID, sizeof(SWVB_BUS_ID));
//The sizeof(WCHAR) is so that we chomp over the terminating UNICODE_NULL.
RtlCopyMemory ( (PCHAR)pmwszBuffer + sizeof(SWVB_BUS_ID) - sizeof(WCHAR), pPdoExt->pmwszHardwareID, ulLength);
NtStatus = STATUS_SUCCESS;
}
else
{
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
}
GCK_DBG_TRACE_PRINT(("First HardwareIDs is %ws\n", pmwszBuffer));
pIrp->IoStatus.Information = (ULONG) pmwszBuffer;
break;
}
case BusQueryInstanceID:
{
//
ULONG ulLength;
PWCHAR pmwszBuffer;
ulLength = MultiSzWByteLength(pPdoExt->pmwszHardwareID) + sizeof(SWVB_INSTANCE_EXT);
pmwszBuffer = (PWCHAR)EX_ALLOCATE_POOL (PagedPool, ulLength);
if (pmwszBuffer)
{
swprintf(pmwszBuffer, SWVB_INSTANCE_ID_TMPLT, pPdoExt->pmwszHardwareID, pPdoExt->ulInstanceNumber);
NtStatus = STATUS_SUCCESS;
}
else
{
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
}
GCK_DBG_TRACE_PRINT(("Instance ID is %ws\n", pmwszBuffer));
pIrp->IoStatus.Information = (ULONG) pmwszBuffer;
break;
}
case BusQueryCompatibleIDs:
pIrp->IoStatus.Information = 0;
NtStatus = STATUS_NOT_SUPPORTED;
break;
}
break;
case IRP_MN_QUERY_PNP_DEVICE_STATE:
GCK_DBG_TRACE_PRINT(("IRP_MN_QUERY_PNP_DEVICE_STATE\n"));
NtStatus = STATUS_SUCCESS;
break;
case IRP_MN_SURPRISE_REMOVAL:
GCK_DBG_TRACE_PRINT(("IRP_MN_SURPRISE_REMOVAL\n"));
// BUGBUG we may need to know that this happened in the future
NtStatus = STATUS_SUCCESS;
break;
//
// These are just completed with success
//
case IRP_MN_QUERY_REMOVE_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_QUERY_REMOVE_DEVICE\n"));
NtStatus = STATUS_SUCCESS;
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_CANCEL_REMOVE_DEVICE\n"));
NtStatus = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_STOP_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_QUERY_STOP_DEVICE\n"));
NtStatus = STATUS_SUCCESS;
break;
case IRP_MN_CANCEL_STOP_DEVICE:
GCK_DBG_TRACE_PRINT(("IRP_MN_CANCEL_STOP_DEVICE\n"));
NtStatus = STATUS_SUCCESS;
break;
//
// These are just completed with their default status.
//
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
GCK_DBG_TRACE_PRINT(("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"));
break;
case IRP_MN_READ_CONFIG:
GCK_DBG_TRACE_PRINT(("IRP_MN_READ_CONFIG\n"));
break;
case IRP_MN_WRITE_CONFIG:
GCK_DBG_TRACE_PRINT(("IRP_MN_WRITE_CONFIG\n"));
break;
case IRP_MN_EJECT:
GCK_DBG_TRACE_PRINT(("IRP_MN_EJECT\n"));
break;
case IRP_MN_SET_LOCK:
GCK_DBG_TRACE_PRINT(("IRP_MN_SET_LOCK\n"));
break;
case IRP_MN_QUERY_INTERFACE:
GCK_DBG_TRACE_PRINT(("IRP_MN_QUERY_INTERFACE\n"));
break;
default:
GCK_DBG_TRACE_PRINT(("Unknown IRP_MJ_PNP minor function = 0x%x\n", pIrpStack->MinorFunction));
}
//
// We are a PDO, there is no-one beneath us, we cannot send IRP's down.
// So we complete with the status set in the above switch/case,
// if not change there, the default is to preserve the status as
// NtStatus = pIrp->IoStatus.Status is done prior to entering the
// switch/case
//
pIrp->IoStatus.Status = NtStatus;
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
GCK_DecRemoveLock(&pPdoExt->RemoveLock);
GCK_DBG_EXIT_PRINT(("Exiting GCK_SWVB_PnP with Status, 0x%0.8x\n", NtStatus));
return NtStatus;
}
/***********************************************************************************
**
** NTSTATUS GCK_SWVB_Power(IN PDEVICE_OBJECT pDeviceObject, IN OUT PIRP pIrp)
**
** @func Handles Power IRPs for Virtual Devices. We only have virtual
** devices so we support any power IRP. Just succeed, sure we handle
** that power level. In the future, we may wish to keep track of what
** state we are in, so we can wake the system, etc.
**
** @rdesc STATUS_SUCCESS
**
*************************************************************************************/
NTSTATUS GCK_SWVB_Power
(
IN PDEVICE_OBJECT pDeviceObject, // @parm Device Object IRP is sent to
IN OUT PIRP pIrp // @parm IRP to process
)
{
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
PIO_STACK_LOCATION pIrpStack;
PSWVB_PDO_EXT pPdoExt = (PSWVB_PDO_EXT)pDeviceObject->DeviceExtension;
ASSERT( GCK_DO_TYPE_SWVB == pPdoExt->ulGckDevObjType);
GCK_DBG_ENTRY_PRINT(("Entering GCK_SWVB_Power\n"));
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
GCK_IncRemoveLock(&pPdoExt->RemoveLock);
switch (pIrpStack->MinorFunction){
case IRP_MN_SET_POWER:
switch (pIrpStack->Parameters.Power.Type) {
case SystemPowerState:
NtStatus = STATUS_SUCCESS;
break;
case DevicePowerState:
NtStatus = STATUS_SUCCESS;
break;
default:
NtStatus = pIrp->IoStatus.Status;
}
break;
case IRP_MN_WAIT_WAKE:
//We just return STATUS_NOT_SUPPORTED as we do not support
//waking the system.
NtStatus = STATUS_NOT_SUPPORTED;
break;
case IRP_MN_POWER_SEQUENCE:
ASSERT(FALSE); //Shouldn't happen
NtStatus = pIrp->IoStatus.Status;
break;
case IRP_MN_QUERY_POWER:
NtStatus = STATUS_SUCCESS;
break;
default:
NtStatus = pIrp->IoStatus.Status;
break;
}
//we are done so signal that we are ready for next one
PoStartNextPowerIrp(pIrp);
ASSERT(NtStatus != STATUS_UNSUCCESSFUL);
pIrp->IoStatus.Status = NtStatus;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
GCK_DecRemoveLock(&pPdoExt->RemoveLock);
GCK_DBG_EXIT_PRINT(("Exiting GCK_Power with Status, 0x%0.8x\n", NtStatus));
return NtStatus;
}