Windows2003-3790/drivers/smartcrd/scutil/pnp.c
2020-09-30 16:53:55 +02:00

812 lines
17 KiB
C

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