|
|
/***************************************************************************
Copyright (c) 2002 Microsoft Corporation
Module Name:
pnp.C
Abstract:
PnP Routines for Smartcard Driver Utility Library
Environment:
Kernel Mode Only
Notes:
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
Revision History:
05/14/2002 : created
Authors:
Randy Aull
****************************************************************************/ #include "pch.h"
#include "pnp.h"
#include "irplist.h"
#include "scutil.h"
#include "scpriv.h"
PNPSTATE SetPnPState( PSCUTIL_EXTENSION pExt, PNPSTATE State ) { PNPSTATE prevState;
prevState = pExt->PrevState; pExt->PrevState = pExt->PnPState; pExt->PnPState = State;
return prevState; }
NTSTATUS ScUtilDefaultPnpHandler( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description: Passes IRP_MJ_PNP to next lower driver
Arguments:
Return Value:
--*/ {
PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension); NTSTATUS status = STATUS_SUCCESS;
__try { SmartcardDebug( DEBUG_TRACE, ("ScUtilDefaultPnpHandler Enter\n"));
IoSkipCurrentIrpStackLocation(Irp); ASSERT(pExt->LowerDeviceObject); status = IoCallDriver(pExt->LowerDeviceObject, Irp);
}
__finally { SmartcardDebug( DEBUG_TRACE, ("ScUtilDefaultPnpHandler Exit : 0x%x\n",status ));
}
return status;
}
NTSTATUS ScUtil_PnP( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension); PIO_STACK_LOCATION irpStack; BOOLEAN deviceRemoved = FALSE;
PSMARTCARD_EXTENSION smartcardExtension = pExt->SmartcardExtension;
ASSERT(pExt);
PAGED_CODE();
__try { SmartcardDebug(DEBUG_TRACE, ("Enter: ScUtil_PnP\n")); status = IoAcquireRemoveLock(pExt->RemoveLock, Irp);
if (!NT_SUCCESS(status)) {
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); __leave;
}
irpStack = IoGetCurrentIrpStackLocation(Irp);
switch (irpStack->MinorFunction) { case IRP_MN_START_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("ScUtil_PnP: IRP_MN_START_DEVICE \n"));
SetPnPState(pExt, DEVICE_STATE_STARTING);
status = ScUtil_ForwardAndWait(DeviceObject, Irp); if (NT_SUCCESS(status)) { status = ScUtilStartDevice(DeviceObject, Irp); }
break;
case IRP_MN_QUERY_REMOVE_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("ScUtil_PnP: IRP_MN_QUERY_REMOVE_DEVICE\n"));
status = ScUtilQueryRemoveDevice(DeviceObject, Irp);
if (!NT_SUCCESS(status)) {
break; }
Irp->IoStatus.Status = STATUS_SUCCESS; status = ScUtilDefaultPnpHandler(DeviceObject, Irp); __leave; case IRP_MN_REMOVE_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("ScUtil_PnP: IRP_MN_REMOVE_DEVICE\n"));
status = ScUtilRemoveDevice(DeviceObject, Irp);
if (NT_SUCCESS(status)) {
deviceRemoved = TRUE;
__leave;
} break;
case IRP_MN_SURPRISE_REMOVAL: SmartcardDebug( DEBUG_DRIVER, ("ScUtil_PnP: IRP_MN_SUPRISE_REMOVE\n"));
status = ScUtilSurpriseRemoval(DeviceObject, Irp);
if (!NT_SUCCESS(status)) {
break;
}
Irp->IoStatus.Status = STATUS_SUCCESS; status = ScUtilDefaultPnpHandler(DeviceObject, Irp); __leave;
case IRP_MN_CANCEL_REMOVE_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("ScUtil_PnP: IRP_MN_CANCEL_REMOVE_DEVICE\n"));
status = ScUtil_ForwardAndWait(DeviceObject, Irp); if (NT_SUCCESS(status)) { status = ScUtilCancelRemoveDevice(DeviceObject, Irp);
} break;
case IRP_MN_STOP_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("ScUtil_PnP: IRP_MN_STOP_DEVICE\n")); status = ScUtilStopDevice(DeviceObject, Irp); if (NT_SUCCESS(status)) {
Irp->IoStatus.Status = STATUS_SUCCESS; status = ScUtilDefaultPnpHandler(DeviceObject, Irp); __leave;
}
break;
case IRP_MN_QUERY_STOP_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("ScUtil_PnP: IRP_MN_QUERY_STOP_DEVICE\n"));
status = ScUtilQueryStopDevice(DeviceObject, Irp);
if (!NT_SUCCESS(status)) { break; } Irp->IoStatus.Status = STATUS_SUCCESS; status = ScUtilDefaultPnpHandler(DeviceObject, Irp);
__leave; // We don't need to complete this so just skip it.
case IRP_MN_CANCEL_STOP_DEVICE: SmartcardDebug( DEBUG_DRIVER, ("ScUtil_PnP: IRP_MN_CANCEL_STOP_DEVICE\n"));
// Lower drivers must handle this irp first
status = ScUtil_ForwardAndWait(DeviceObject, Irp);
if (NT_SUCCESS(status)) {
status = ScUtilCancelStopDevice(DeviceObject, Irp);
} break;
case IRP_MN_QUERY_CAPABILITIES: SmartcardDebug( DEBUG_DRIVER, ("ScUtil_PnP: IRP_MN_QUERY_CAPABILITIES\n"));
status = ScUtil_ForwardAndWait(DeviceObject, Irp); if (NT_SUCCESS(status)) {
pExt->DeviceCapabilities = *irpStack->Parameters.DeviceCapabilities.Capabilities;
}
break;
default: SmartcardDebug( DEBUG_DRIVER, ("ScUtil_PnP: IRP_MN_...%lx\n", irpStack->MinorFunction ));
status = ScUtilDefaultPnpHandler(DeviceObject, Irp); __leave; // We don't need to complete this so just skip it.
}
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
__finally {
if (deviceRemoved == FALSE) {
IoReleaseRemoveLock(pExt->RemoveLock, Irp); }
SmartcardDebug(DEBUG_TRACE, ("Exit: ScUtil_PnP (0x%x)\n", status)); }
return status;
}
NTSTATUS ScUtilStartDevice( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description: Handles the IRP_MN_START_DEVICE Gets the usb descriptors from the reader and configures it. Also starts "polling" the interrupt pipe
Arguments:
Return Value:
--*/ {
NTSTATUS status = STATUS_UNSUCCESSFUL; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension); __try {
SmartcardDebug( DEBUG_TRACE, ("ScUtilStartDevice Enter\n" ));
status = pExt->StartDevice(DeviceObject, Irp);
if (!NT_SUCCESS(status)) { SetPnPState(pExt, DEVICE_STATE_START_FAILURE); __leave; } SetPnPState(pExt, DEVICE_STATE_START_SUCCESS);
StartIoctls(pExt); IncIoCount(pExt);
status = IoSetDeviceInterfaceState(&pExt->DeviceName, TRUE);
}
__finally {
SmartcardDebug( DEBUG_TRACE, ("ScUtilStartDevice Exit : 0x%x\n", status ));
}
return status;
}
NTSTATUS ScUtilStopDevice( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description: Handles IRP_MN_STOP_DEVICE Stops "polling" the interrupt pipe and frees resources allocated in StartDevice
Arguments:
Return Value:
--*/ {
NTSTATUS status = STATUS_UNSUCCESSFUL; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension);
__try {
SmartcardDebug( DEBUG_TRACE, ("ScUtilStopDevice Enter\n" ));
if (!DeviceObject) { __leave; }
pExt->StopDevice(DeviceObject, Irp);
}
__finally {
SmartcardDebug( DEBUG_TRACE, ("ScUtilStopDevice Exit : 0x%x\n", status ));
}
return status;
}
NTSTATUS ScUtilQueryRemoveDevice( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description: Handles IRP_MN_QUERY_REMOVE Disables the reader and prepares it for the IRP_MN_REMOVE
Arguments:
Return Value:
--*/ {
NTSTATUS status = STATUS_SUCCESS; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension);
__try {
SmartcardDebug( DEBUG_TRACE, ("ScUtilQueryRemoveDevice Enter\n" ));
// check if the reader has been opened
if (pExt->ReaderOpen) { status = STATUS_UNSUCCESSFUL; __leave;
}
SetPnPState(pExt, DEVICE_STATE_REMOVING);
StopIoctls(pExt); }
__finally {
SmartcardDebug( DEBUG_TRACE, ("ScUtilQueryRemoveDevice Exit : 0x%x\n", status ));
}
return status;
}
NTSTATUS ScUtilCancelRemoveDevice( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description: handles IRP_MN_CANCEL_REMOVE undoes actions in QueryRemove
Arguments:
Return Value: STATUS_SUCCESS
--*/ {
NTSTATUS status = STATUS_UNSUCCESSFUL; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension);
__try {
SmartcardDebug( DEBUG_TRACE, ("ScUtilCancelRemoveDevice Enter\n" ));
if (pExt->PnPState != DEVICE_STATE_REMOVING) { status = STATUS_SUCCESS; __leave; }
if (pExt->PrevState == DEVICE_STATE_START_SUCCESS) {
StartIoctls(pExt); }
SetPnPState(pExt, pExt->PrevState);
status = STATUS_SUCCESS;
}
__finally {
SmartcardDebug( DEBUG_TRACE, ("ScUtilCancelRemoveDevice Exit : 0x%x\n", status ));
}
return status;
}
NTSTATUS ScUtilRemoveDevice( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description: handles IRP_MN_REMOVE_DEVICE stops and unloads the device.
Arguments:
Return Value:
--*/ {
NTSTATUS status = STATUS_UNSUCCESSFUL; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension); __try {
SmartcardDebug( DEBUG_TRACE, ("ScUtilRemoveDevice Enter\n" ));
if (pExt->PnPState != DEVICE_STATE_SUPRISE_REMOVING) {
FailIoctls(pExt);
status = IoSetDeviceInterfaceState(&pExt->DeviceName, FALSE);
if (pExt->FreeResources) { pExt->FreeResources(DeviceObject, Irp); } }
IoReleaseRemoveLockAndWait(pExt->RemoveLock, Irp);
SetPnPState(pExt, DEVICE_STATE_REMOVED);
Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (pExt->LowerDeviceObject, Irp);
pExt->RemoveDevice(DeviceObject, Irp);
// delete the symbolic link
if( pExt->DeviceName.Buffer != NULL ) {
RtlFreeUnicodeString(&pExt->DeviceName); pExt->DeviceName.Buffer = NULL;
}
if( pExt->SmartcardExtension->OsData != NULL ) {
SmartcardExit(pExt->SmartcardExtension);
}
if (pExt->SmartcardExtension->ReaderExtension != NULL) {
ExFreePool(pExt->SmartcardExtension->ReaderExtension); pExt->SmartcardExtension->ReaderExtension = NULL;
}
// Detach from the usb driver
if (pExt->LowerDeviceObject) {
IoDetachDevice(pExt->LowerDeviceObject); pExt->LowerDeviceObject = NULL;
}
ExFreePool(pExt);
// delete the device object
IoDeleteDevice(DeviceObject); }
__finally {
SmartcardDebug( DEBUG_TRACE, ("ScUtilRemoveDevice Exit : 0x%x\n", status ));
}
return status;
}
NTSTATUS ScUtilSurpriseRemoval( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description: handles IRP_MN_SUPRISE_REMOVE Does the same as QueryRemove Arguments:
Return Value:
--*/ {
NTSTATUS status = STATUS_UNSUCCESSFUL; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension);
__try {
SmartcardDebug( DEBUG_TRACE, ("ScUtilSurpriseRemoval Enter\n" )); FailIoctls(pExt); SetPnPState(pExt, DEVICE_STATE_REMOVING); status = IoSetDeviceInterfaceState(&pExt->DeviceName, FALSE);
if (pExt->FreeResources) { pExt->FreeResources(DeviceObject, Irp); }
status = STATUS_SUCCESS;
}
__finally {
SmartcardDebug( DEBUG_TRACE, ("ScUtilSurpriseRemoval Exit : 0x%x\n", status ));
}
return status;
}
NTSTATUS ScUtilQueryStopDevice( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description: handles IRP_MN_QUERY_STOP Stops interrupt "polling" and waits for I/O to complete
Arguments:
Return Value:
--*/ {
NTSTATUS status = STATUS_UNSUCCESSFUL; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension);
__try {
SmartcardDebug( DEBUG_TRACE, ("ScUtilQueryStopDevice Enter\n"));
if (!NT_SUCCESS(status)) {
__leave;
}
SetPnPState(pExt, DEVICE_STATE_STOPPING);
StopIoctls(pExt); DecIoCount(pExt);
// Wait for all IO to complete before stopping
status = KeWaitForSingleObject(&pExt->OkToStop, Executive, KernelMode, FALSE, NULL);
if (!NT_SUCCESS(status)) {
__leave;
} }
__finally {
SmartcardDebug( DEBUG_TRACE, ("ScUtilQueryStopDevice Exit : 0x%x\n", status ));
}
return status;
}
NTSTATUS ScUtilCancelStopDevice( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description: Restarts Interrupt polling
Arguments:
Return Value:
--*/ {
NTSTATUS status = STATUS_UNSUCCESSFUL; PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension);
__try {
SmartcardDebug( DEBUG_TRACE, ("ScUtilCancelStopDevice Enter\n"));
SetPnPState(pExt, pExt->PrevState);
IncIoCount(pExt);
StartIoctls(pExt); status = STATUS_SUCCESS;
}
__finally {
SmartcardDebug( DEBUG_TRACE, ("ScUtilCancelStopDevice Exit : 0x%x\n", status ));
}
return status;
}
|