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