windows-nt/Source/XPSP1/NT/printscan/wia/kernel/serscan/pnppwr.c

621 lines
17 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
pnp.c
Abstract:
This module contains the code for a serial imaging devices driver
supporting PnP functionality
Author:
Vlad Sadovsky vlads 10-April-1998
Environment:
Kernel mode
Revision History :
vlads 04/10/1998 Created first draft
--*/
#include "serscan.h"
#include "serlog.h"
//#include <ntpoapi.h>
extern ULONG SerScanDebugLevel;
extern const PHYSICAL_ADDRESS PhysicalZero ;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, SerScanPnp)
#pragma alloc_text(PAGE, SerScanPower)
#endif
NTSTATUS
SerScanPnp (
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
/*++
Routine Description:
This routine handles all PNP IRPs, dispatching them as appropriate .
Arguments:
pDeviceObject - represents a device
pIrp - PNP Irp
Return Value:
STATUS_SUCCESS - if successful.
STATUS_UNSUCCESSFUL - otherwise.
--*/
{
NTSTATUS Status ;
PDEVICE_EXTENSION Extension;
PIO_STACK_LOCATION pIrpStack;
PVOID pObject;
ULONG NewReferenceCount;
NTSTATUS ReturnStatus;
pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
Extension = pDeviceObject->DeviceExtension;
Status = STATUS_SUCCESS;
DebugDump(SERINITDEV,("Entering PnP Dispatcher\n"));
switch (pIrpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
//
// Initialize PendingIoEvent. Set the number of pending i/o requests for this device to 1.
// When this number falls to zero, it is okay to remove, or stop the device.
//
DebugDump(SERINITDEV,("Entering Start Device \n"));
KeInitializeEvent(&Extension -> PdoStartEvent, SynchronizationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(pIrp);
Status = WaitForLowerDriverToCompleteIrp(
Extension->LowerDevice,
pIrp,
&Extension->PdoStartEvent);
if (!NT_SUCCESS(Status)) {
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return (Status);
}
#ifdef CREATE_SYMBOLIC_NAME
//
// Now setup the symbolic link for windows.
//
Status = IoCreateUnprotectedSymbolicLink(&Extension->SymbolicLinkName, &Extension->ClassName);
if (NT_SUCCESS(Status)) {
// We were able to create the symbolic link, so record this
// value in the extension for cleanup at unload time.
Extension->CreatedSymbolicLink = TRUE;
// Write out the result of the symbolic link to the registry.
Status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
L"Serial Scanners",
Extension->ClassName.Buffer,
REG_SZ,
Extension->SymbolicLinkName.Buffer,
Extension->SymbolicLinkName.Length + sizeof(WCHAR));
if (!NT_SUCCESS(Status)) {
//
// It didn't work. Just go to cleanup.
//
DebugDump(SERERRORS,
("SerScan: Couldn't create the device map entry\n"
"-------- for port %wZ\n",
&Extension->ClassName));
SerScanLogError(pDeviceObject->DriverObject,
pDeviceObject,
PhysicalZero,
PhysicalZero,
0,
0,
0,
6,
Status,
SER_NO_DEVICE_MAP_CREATED);
}
} else {
//
// Couldn't create the symbolic link.
//
Extension->CreatedSymbolicLink = FALSE;
ExFreePool(Extension->SymbolicLinkName.Buffer);
Extension->SymbolicLinkName.Buffer = NULL;
DebugDump(SERERRORS,
("SerScan: Couldn't create the symbolic link\n"
"-------- for port %wZ\n",
&Extension->ClassName));
SerScanLogError(pDeviceObject->DriverObject,
pDeviceObject,
PhysicalZero,
PhysicalZero,
0,
0,
0,
5,
Status,
SER_NO_SYMLINK_CREATED);
}
#endif
ExFreePool(Extension->ClassName.Buffer);
Extension->ClassName.Buffer = NULL;
//
// Ignore status of link registry write - always succeed
//
//
// Clear InInit flag to indicate device object can be used
//
pDeviceObject->Flags &= ~(DO_DEVICE_INITIALIZING);
pIrp->IoStatus.Status = Status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return (Status);
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
//
// Always pass to lower device in stack after indicating that we don't object
//
DebugDump(SERALWAYS,("IRP_MN_QUERY_REMOVE_DEVICE\n"));
Extension->Removing = TRUE;
IoCopyCurrentIrpStackLocationToNext( pIrp );
return (IoCallDriver(Extension->LowerDevice, pIrp));
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
//
// Always pass to lower device in stack , reset indicator as somebody canceled
//
DebugDump(SERALWAYS,("IRP_MN_CANCEL_REMOVE_DEVICE\n"));
Extension->Removing = FALSE;
//
// Kill symbolic link
//
if (Extension->CreatedSymbolicLink) {
IoDeleteSymbolicLink(&Extension->SymbolicLinkName);
Extension->CreatedSymbolicLink = FALSE;
}
IoCopyCurrentIrpStackLocationToNext( pIrp );
return (IoCallDriver(Extension->LowerDevice, pIrp));
break;
case IRP_MN_SURPRISE_REMOVAL:
//
// Should not ever happen with us, but still process
//
DebugDump(SERALWAYS,("IRP_MN_SURPRISE_REMOVAL\n"));
Extension->Removing = TRUE;
//
// Get rid of the symbolic link
//
SerScanHandleSymbolicLink(
Extension->Pdo,
&Extension->InterfaceNameString,
FALSE
);
#ifdef USE_EXECUTIVE_RESOURCE
ExAcquireResourceExclusiveLite(
&Extension->Resource,
TRUE
);
#else
ExAcquireFastMutex(&Extension->Mutex);
#endif
pObject = InterlockedExchangePointer(&Extension->AttachedFileObject,NULL);
if (pObject) {
ObDereferenceObject(pObject);
}
pObject = InterlockedExchangePointer(&Extension->AttachedDeviceObject,NULL);
if (pObject) {
ObDereferenceObject(pObject);
}
#ifdef USE_EXECUTIVE_RESOURCE
ExReleaseResourceLite(&Extension->Resource);
#else
ExReleaseFastMutex(&Extension->Mutex);
#endif
IoCopyCurrentIrpStackLocationToNext( pIrp );
return (IoCallDriver(Extension->LowerDevice, pIrp));
break;
case IRP_MN_REMOVE_DEVICE:
DebugDump(SERALWAYS,("IRP_MN_REMOVE_DEVICE\n"));
DebugDump(SERINITDEV,("Entering PnP Remove Device\n"));
//
// Stop new requests - device is being removed
//
Extension->Removing = TRUE;
//
// Get rid of the symbolic link
//
SerScanHandleSymbolicLink(
Extension->Pdo,
&Extension->InterfaceNameString,
FALSE
);
#ifdef USE_EXECUTIVE_RESOURCE
ExAcquireResourceExclusiveLite(
&Extension->Resource,
TRUE
);
#else
ExAcquireFastMutex(&Extension->Mutex);
#endif
pObject = InterlockedExchangePointer(&Extension->AttachedFileObject,NULL);
if (pObject) {
ObDereferenceObject(pObject);
}
pObject = InterlockedExchangePointer(&Extension->AttachedDeviceObject,NULL);
if (pObject) {
ObDereferenceObject(pObject);
}
#ifdef USE_EXECUTIVE_RESOURCE
ExReleaseResourceLite(&Extension->Resource);
#else
ExReleaseFastMutex(&Extension->Mutex);
#endif
//
// Send IRP down to lower device
//
IoCopyCurrentIrpStackLocationToNext( pIrp );
ReturnStatus = IoCallDriver(Extension->LowerDevice, pIrp);
//
// Decrement ref count
//
NewReferenceCount = InterlockedDecrement(&Extension->ReferenceCount);
if (NewReferenceCount != 0) {
//
// Wait for any io requests pending in our driver to
// complete before finishing the remove
//
KeWaitForSingleObject(&Extension -> RemoveEvent,
Suspended,
KernelMode,
FALSE,
NULL);
}
// ASSERT(&Extension->ReferenceCount == 0);
#ifdef USE_EXECUTIVE_RESOURCE
ExDeleteResourceLite(&Extension->Resource);
#endif
DebugDump(SERALWAYS,("IRP_MN_QUERY_REMOVE_DEVICE - Calling IoDeleteDevice - gone\n"));
IoDetachDevice(Extension->LowerDevice);
//
// Free allocated resource.
//
if(NULL != Extension->ClassName.Buffer){
ExFreePool(Extension->ClassName.Buffer);
} // if(NULL != Extension->ClassName.Buffer)
if(NULL != Extension->SymbolicLinkName.Buffer){
ExFreePool(Extension->SymbolicLinkName.Buffer);
} // if(NULL != Extension->SymbolicLinkName.Buffer)
IoDeleteDevice(pDeviceObject);
return ReturnStatus;
break;
case IRP_MN_STOP_DEVICE:
//
// Pass down
//
DebugDump(SERALWAYS,("IRP_MN_STOP_DEVICE\n"));
IoCopyCurrentIrpStackLocationToNext( pIrp );
return (IoCallDriver(Extension->LowerDevice, pIrp));
break;
case IRP_MN_QUERY_STOP_DEVICE:
//
// Check open counts
//
DebugDump(SERALWAYS,("IRP_MN_QUERY_STOP_DEVICE\n"));
if (Extension->OpenCount > 0 ) {
DebugDump(SERALWAYS,("Rejecting QUERY_STOP_DEVICE\n"));
pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_UNSUCCESSFUL;
}
IoCopyCurrentIrpStackLocationToNext( pIrp );
return (IoCallDriver(Extension->LowerDevice, pIrp));
break;
case IRP_MN_CANCEL_STOP_DEVICE:
//
// Nothing to do here, but pass to lower
//
DebugDump(SERALWAYS,("IRP_MN_CANCEL_STOP_DEVICE\n"));
IoCopyCurrentIrpStackLocationToNext( pIrp );
return (IoCallDriver(Extension->LowerDevice, pIrp));
break;
case IRP_MN_QUERY_CAPABILITIES:
{
ULONG i;
KEVENT WaitEvent;
//
// Send this down to the PDO first
//
KeInitializeEvent(&WaitEvent, SynchronizationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(pIrp);
Status=WaitForLowerDriverToCompleteIrp(
Extension->LowerDevice,
pIrp,
&WaitEvent
);
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
for (i = PowerSystemUnspecified; i < PowerSystemMaximum; i++) {
Extension->SystemPowerStateMap[i]=PowerDeviceD3;
}
for (i = PowerSystemUnspecified; i < PowerSystemHibernate; i++) {
Extension->SystemPowerStateMap[i]=pIrpStack->Parameters.DeviceCapabilities.Capabilities->DeviceState[i];
}
Extension->SystemPowerStateMap[PowerSystemWorking]=PowerDeviceD0;
Extension->SystemWake=pIrpStack->Parameters.DeviceCapabilities.Capabilities->SystemWake;
Extension->DeviceWake=pIrpStack->Parameters.DeviceCapabilities.Capabilities->DeviceWake;
IoCompleteRequest(
pIrp,
IO_NO_INCREMENT
);
return Status;
}
break;
default:
//
// Unknown function - pass down
//
DebugDump(SERALWAYS,("Passing Pnp Irp down. MnFunc=%x , status = %x\n",pIrpStack->MinorFunction, Status));
IoCopyCurrentIrpStackLocationToNext( pIrp );
return (IoCallDriver(Extension->LowerDevice, pIrp));
break;
}
//
// Complete the IRP...
//
if (!NT_SUCCESS(Status)) {
pIrp -> IoStatus.Status = Status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
}
else {
DebugDump(SERALWAYS,("Passing Pnp Irp down, status = %x\n", Status));
IoCopyCurrentIrpStackLocationToNext(pIrp);
Status = IoCallDriver(Extension->LowerDevice, pIrp);
}
return( Status );
}
VOID
DevicePowerCompleteRoutine(
PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
return;
}
NTSTATUS
SerScanPower(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
/*++
Routine Description:
Process the Power IRPs sent to the PDO for this device.
Arguments:
pDeviceObject - pointer to the functional device object (FDO) for this device.
pIrp - pointer to an I/O Request Packet
Return Value:
NT status code
--*/
{
NTSTATUS Status;
PDEVICE_EXTENSION Extension = pDeviceObject->DeviceExtension;
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
POWER_STATE PowerState;
PAGED_CODE();
Status = STATUS_SUCCESS;
switch (pIrpStack->MinorFunction) {
case IRP_MN_SET_POWER:
if (pIrpStack->Parameters.Power.Type == SystemPowerState) {
//
// system power state change
//
//
// request the change in device power state based on systemstate map
//
PowerState.DeviceState=Extension->SystemPowerStateMap[pIrpStack->Parameters.Power.State.SystemState];
PoRequestPowerIrp(
Extension->Pdo,
IRP_MN_SET_POWER,
PowerState,
DevicePowerCompleteRoutine,
pIrp,
NULL
);
} else {
//
// changing device state
//
PoSetPowerState(
Extension->Pdo,
pIrpStack->Parameters.Power.Type,
pIrpStack->Parameters.Power.State
);
}
break;
case IRP_MN_QUERY_POWER:
pIrp->IoStatus.Status = STATUS_SUCCESS;
break;
default:
break;
}
PoStartNextPowerIrp(pIrp);
IoSkipCurrentIrpStackLocation(pIrp);
Status=PoCallDriver(Extension->LowerDevice, pIrp);
return Status;
}