Windows-Server-2003/drivers/smartcrd/cmbp0/cmbp0pnp.c

1013 lines
36 KiB
C

/*****************************************************************************
@doc INT EXT
******************************************************************************
* $ProjectName: $
* $ProjectRevision: $
*-----------------------------------------------------------------------------
* $Source: z:/pr/cmbp0/sw/cmbp0.ms/rcs/cmbp0pnp.c $
* $Revision: 1.4 $
*-----------------------------------------------------------------------------
* $Author: TBruendl $
*-----------------------------------------------------------------------------
* History: see EOF
*-----------------------------------------------------------------------------
*
* Copyright © 2000 OMNIKEY AG
******************************************************************************/
#include <cmbp0wdm.h>
#include <cmbp0pnp.h>
#include <cmbp0scr.h>
#include <cmbp0log.h>
/*****************************************************************************
Routine Description:
???
Arguments:
Return Value:
******************************************************************************/
NTSTATUS CMMOB_AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
{
NTSTATUS NTStatus;
PDEVICE_OBJECT DeviceObject = NULL;
SmartcardDebug(DEBUG_TRACE,
("%s!AddDevice: Enter\n",DRIVER_NAME));
try {
PDEVICE_EXTENSION DeviceExtension;
NTStatus = CMMOB_CreateDevice(DriverObject, PhysicalDeviceObject, &DeviceObject);
if (NTStatus != STATUS_SUCCESS) {
leave;
}
DeviceExtension = DeviceObject->DeviceExtension;
DeviceExtension->AttachedDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject,
PhysicalDeviceObject);
if (DeviceExtension->AttachedDeviceObject == NULL) {
NTStatus = STATUS_UNSUCCESSFUL;
leave;
}
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
}
finally {
if (NTStatus != STATUS_SUCCESS) {
CMMOB_UnloadDevice(DeviceObject);
}
}
SmartcardDebug(DEBUG_TRACE,
("%s!AddDevice: Exit %x\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Send an Irp to the pcmcia driver and wait until the pcmcia driver has
finished the request.
To make sure that the pcmcia driver will not complete the Irp we first
initialize an event and set our own completion routine for the Irp.
When the pcmcia driver has processed the Irp the completion routine will
set the event and tell the IO manager that more processing is required.
By waiting for the event we make sure that we continue only if the pcmcia
driver has processed the Irp completely.
Arguments:
DeviceObject context of call
Irp Irp to send to the pcmcia driver
Return Value:
NTStatus returned by the pcmcia driver
******************************************************************************/
NTSTATUS CMMOB_CallPcmciaDriver(
IN PDEVICE_OBJECT AttachedDeviceObject,
IN PIRP Irp
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpStack, IrpNextStack;
KEVENT Event;
/*
SmartcardDebug(DEBUG_TRACE,
("%s!CMMOB_CallPcmciaDriver: Enter\n",DRIVER_NAME ));
*/
//
// Prepare everything to call the underlying driver
//
IrpStack = IoGetCurrentIrpStackLocation(Irp);
IrpNextStack = IoGetNextIrpStackLocation(Irp);
//
// Copy our stack to the next stack location.
//
*IrpNextStack = *IrpStack;
//
// initialize an event for process synchronization. the event is passed
// to our completion routine and will be set if the pcmcia driver is done
//
KeInitializeEvent(&Event,
NotificationEvent,
FALSE);
//
// Our IoCompletionRoutine sets only our event
//
IoSetCompletionRoutine (Irp,
CMMOB_PcmciaCallComplete,
&Event,
TRUE,
TRUE,
TRUE);
//
// Call the pcmcia driver
//
if (IrpStack->MajorFunction == IRP_MJ_POWER) {
NTStatus = PoCallDriver(AttachedDeviceObject,Irp);
} else {
NTStatus = IoCallDriver(AttachedDeviceObject,Irp);
}
//
// Wait until the pcmcia driver has processed the Irp
//
if (NTStatus == STATUS_PENDING) {
NTStatus = KeWaitForSingleObject(&Event,
Executive,
KernelMode,
FALSE,
NULL);
if (NTStatus == STATUS_SUCCESS) {
NTStatus = Irp->IoStatus.Status;
}
}
/*
SmartcardDebug(DEBUG_TRACE,
("%s!CMMOB_CallPcmciaDriver: Exit %x\n",DRIVER_NAME,NTStatus));
*/
return NTStatus;
}
/*****************************************************************************
Routine Description:
Completion routine for an Irp sent to the pcmcia driver. The event will
be set to notify that the pcmcia driver is done. The routine will not
'complete' the Irp, so the caller of CMMOB_CallPcmciaDriver can continue.
Arguments:
DeviceObject context of call
Irp Irp to complete
Event Used by CMMOB_CallPcmciaDriver for process synchronization
Return Value:
STATUS_CANCELLED Irp was cancelled by the IO manager
STATUS_MORE_PROCESSING_REQUIRED Irp will be finished by caller of
CMMOB_CallPcmciaDriver
******************************************************************************/
NTSTATUS CMMOB_PcmciaCallComplete (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PKEVENT Event
)
{
UNREFERENCED_PARAMETER (DeviceObject);
if (Irp->Cancel) {
Irp->IoStatus.Status = STATUS_CANCELLED;
}
KeSetEvent (Event, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
/*****************************************************************************
Routine Description:
driver callback for pnp manager
Request: Action:
IRP_MN_START_DEVICE Notify the pcmcia driver about the new device
and start the device
IRP_MN_STOP_DEVICE Free all resources used by the device and tell
the pcmcia driver that the device was stopped
IRP_MN_QUERY_REMOVE_DEVICE If the device is opened (i.e. in use) an error will
be returned to prevent the PnP manager to stop
the driver
IRP_MN_CANCEL_REMOVE_DEVICE just notify that we can continue without any
restrictions
IRP_MN_REMOVE_DEVICE notify the pcmcia driver that the device was
removed, stop & unload the device
All other requests will be passed to the pcmcia driver to ensure correct processing.
Arguments:
Device Object context of call
Irp irp from the PnP manager
Return Value:
STATUS_SUCCESS
STATUS_UNSUCCESSFUL
NTStatus returned by pcmcia driver
******************************************************************************/
NTSTATUS CMMOB_PnPDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION IrpStack;
PDEVICE_OBJECT AttachedDeviceObject;
PDEVICE_CAPABILITIES DeviceCapabilities;
KIRQL irql;
LONG i;
BOOLEAN irpSkipped = FALSE;
BOOLEAN removed = FALSE;
SmartcardDebug(DEBUG_TRACE,
("%s!PnPDeviceControl: Enter\n",DRIVER_NAME ));
NTStatus = SmartcardAcquireRemoveLock(&DeviceExtension->SmartcardExtension);
ASSERT(NTStatus == STATUS_SUCCESS);
if (NTStatus != STATUS_SUCCESS) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = NTStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return NTStatus;
}
AttachedDeviceObject = DeviceExtension->AttachedDeviceObject;
// Irp->IoStatus.Information = 0;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
//
// Now look what the PnP manager wants...
//
#ifdef DBG
if (IrpStack->MinorFunction <= IRP_PNP_MN_FUNC_MAX) {
SmartcardDebug(DEBUG_DRIVER,
("%s!PnPDeviceControl: %s received\n",DRIVER_NAME,
szPnpMnFuncDesc[IrpStack->MinorFunction] ));
}
#endif
switch (IrpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
//
// We have to call the underlying driver first
//
NTStatus = CMMOB_CallPcmciaDriver(AttachedDeviceObject,Irp);
if (NT_SUCCESS(NTStatus)) {
//
// Now we should connect to our resources (Irql, Io etc.)
//
NTStatus = CMMOB_StartDevice(DeviceObject,
&IrpStack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0]);
}
break;
case IRP_MN_QUERY_STOP_DEVICE:
KeAcquireSpinLock(&DeviceExtension->SpinLockIoCount, &irql);
if (DeviceExtension->lIoCount > 0) {
// we refuse to stop if we have pending io
KeReleaseSpinLock(&DeviceExtension->SpinLockIoCount, irql);
NTStatus = STATUS_DEVICE_BUSY;
} else {
// stop processing requests
KeClearEvent(&DeviceExtension->ReaderStarted);
KeReleaseSpinLock(&DeviceExtension->SpinLockIoCount, irql);
NTStatus = CMMOB_CallPcmciaDriver(AttachedDeviceObject, Irp);
}
break;
case IRP_MN_CANCEL_STOP_DEVICE:
NTStatus = CMMOB_CallPcmciaDriver(AttachedDeviceObject, Irp);
ASSERT(NTStatus == STATUS_SUCCESS);
// we can continue to process requests
DeviceExtension->lIoCount = 0;
KeSetEvent(&DeviceExtension->ReaderStarted, 0, FALSE);
break;
case IRP_MN_STOP_DEVICE:
//
// Stop the device. Aka disconnect from our resources
//
CMMOB_StopDevice(DeviceObject);
NTStatus = CMMOB_CallPcmciaDriver(AttachedDeviceObject, Irp);
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
//
// Remove our device
//
if (DeviceExtension->lOpenCount > 0) {
NTStatus = STATUS_UNSUCCESSFUL;
} else {
NTStatus = IoSetDeviceInterfaceState(&DeviceExtension->PnPDeviceName,
FALSE);
ASSERT(NTStatus == STATUS_SUCCESS);
if (NTStatus != STATUS_SUCCESS) {
break;
}
NTStatus = CMMOB_CallPcmciaDriver(AttachedDeviceObject, Irp);
}
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
//
// Removal of device has been cancelled
//
NTStatus = CMMOB_CallPcmciaDriver(AttachedDeviceObject, Irp);
if (NTStatus == STATUS_SUCCESS) {
NTStatus = IoSetDeviceInterfaceState(&DeviceExtension->PnPDeviceName,
TRUE);
}
ASSERT(NTStatus == STATUS_SUCCESS);
break;
case IRP_MN_REMOVE_DEVICE:
//
// Remove our device
//
CMMOB_StopDevice(DeviceObject);
// Wait until we can safely unload the device
SmartcardReleaseRemoveLockAndWait(&DeviceExtension->SmartcardExtension);
CMMOB_UnloadDevice(DeviceObject);
removed = TRUE;
NTStatus = CMMOB_CallPcmciaDriver(AttachedDeviceObject, Irp);
break;
case IRP_MN_QUERY_CAPABILITIES:
//
// Query device capabilities
//
//
// Get the packet.
//
DeviceCapabilities=IrpStack->Parameters.DeviceCapabilities.Capabilities;
if (DeviceCapabilities->Version < 1 ||
DeviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES)) {
//
// We don't support this version. Fail the requests
//
NTStatus = STATUS_UNSUCCESSFUL;
break;
}
//
// Set the capabilities.
//
// We cannot wake the system.
DeviceCapabilities->SystemWake = PowerSystemUnspecified;
DeviceCapabilities->DeviceWake = PowerDeviceUnspecified;
// We have no latencies
DeviceCapabilities->D1Latency = 0;
DeviceCapabilities->D2Latency = 0;
DeviceCapabilities->D3Latency = 0;
// No locking or ejection
DeviceCapabilities->LockSupported = FALSE;
DeviceCapabilities->EjectSupported = FALSE;
// Device can be physically removed.
DeviceCapabilities->Removable = TRUE;
// No docking device
DeviceCapabilities->DockDevice = FALSE;
// Device can not be removed any time
// it has a removable media
DeviceCapabilities->SurpriseRemovalOK = FALSE;
//
// Call the next lower driver
//
NTStatus = CMMOB_CallPcmciaDriver(AttachedDeviceObject, Irp);
//
// Now look at the relation system state / device state
//
{
SmartcardDebug( DEBUG_DRIVER,
("%s!PnPDeviceControl: systemstate to devicestate mapping\n",DRIVER_NAME ));
for (i=1; i<PowerSystemMaximum; i++) {
SmartcardDebug(DEBUG_DRIVER,
("%s!PnPDeviceControl: %s -> %s\n",DRIVER_NAME,
szSystemPowerState[i],szDevicePowerState[DeviceCapabilities->DeviceState[i]] ));
if (DeviceCapabilities->DeviceState[i] != PowerDeviceD3 &&
(DeviceCapabilities->DeviceState[i] != PowerDeviceD0 ||
i >= PowerSystemSleeping3)) {
DeviceCapabilities->DeviceState[i]=PowerDeviceD3;
SmartcardDebug(DEBUG_DRIVER,
("%s!PnPDeviceControl: altered to %s -> %s\n",DRIVER_NAME,
szSystemPowerState[i],szDevicePowerState[DeviceCapabilities->DeviceState[i]] ));
}
}
}
// Store DeviceCapabilities in our DeviceExtension for later use
RtlCopyMemory(&DeviceExtension->DeviceCapabilities,DeviceCapabilities,
sizeof(DeviceExtension->DeviceCapabilities));
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
//
// Query device relations
//
SmartcardDebug(DEBUG_DRIVER,
("%s!PnPDeviceControl: Requested relation = %s\n",DRIVER_NAME,
szDeviceRelation[IrpStack->Parameters.QueryDeviceRelations.Type] ));
NTStatus = CMMOB_CallPcmciaDriver(AttachedDeviceObject, Irp);
irpSkipped = TRUE;
break;
default:
//
// This might be an Irp that is only useful
// for the underlying bus driver
//
NTStatus = CMMOB_CallPcmciaDriver(AttachedDeviceObject, Irp);
irpSkipped = TRUE;
break;
}
if (!irpSkipped) {
Irp->IoStatus.Status = NTStatus;
}
IoCompleteRequest(Irp,IO_NO_INCREMENT);
if (removed == FALSE) {
SmartcardReleaseRemoveLock(&DeviceExtension->SmartcardExtension);
}
SmartcardDebug(DEBUG_TRACE,
( "%s!PnPDeviceControl: Exit %x\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
This function is called when the underlying stacks
completed the power transition.
******************************************************************************/
VOID CMMOB_SystemPowerCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PKEVENT Event,
IN PIO_STATUS_BLOCK IoStatus
)
{
UNREFERENCED_PARAMETER (DeviceObject);
UNREFERENCED_PARAMETER (MinorFunction);
UNREFERENCED_PARAMETER (PowerState);
SmartcardDebug(DEBUG_TRACE,
("%s!SystemPowerCompletion: Enter\n",DRIVER_NAME));
SmartcardDebug(DEBUG_DRIVER,
("%s!SystemPowerCompletion: Status of completed IRP = %x\n",DRIVER_NAME,IoStatus->Status));
KeSetEvent(Event, 0, FALSE);
SmartcardDebug(DEBUG_TRACE,
("%s!SystemPowerCompletion: Exit\n",DRIVER_NAME));
}
/*****************************************************************************
Routine Description:
This routine is called after the underlying stack powered
UP the serial port, so it can be used again.
******************************************************************************/
NTSTATUS CMMOB_DevicePowerCompletion (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PSMARTCARD_EXTENSION SmartcardExtension
)
{
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS NTStatus;
UCHAR state;
KIRQL irql;
SmartcardDebug(DEBUG_TRACE,
("%s!DevicePowerCompletion: Enter\n",DRIVER_NAME));
SmartcardDebug(DEBUG_DRIVER,
("%s!DevicePowerCompletion: IRQL %i\n",DRIVER_NAME,KeGetCurrentIrql()));
//
// If a card was present before power down or now there is
// a card in the reader, we complete any pending card monitor
// request, since we do not really know what card is now in the
// reader.
//
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
if (SmartcardExtension->ReaderExtension->fCardPresent ||
SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT) {
SmartcardExtension->ReaderExtension->ulOldCardState = UNKNOWN;
SmartcardExtension->ReaderExtension->ulNewCardState = UNKNOWN;
}
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
KeSetEvent(&DeviceExtension->CanRunUpdateThread, 0, FALSE);
// save the current power state of the reader
SmartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderWorking;
SmartcardReleaseRemoveLock(SmartcardExtension);
// inform the power manager of our state.
PoSetPowerState (DeviceObject,
DevicePowerState,
IrpStack->Parameters.Power.State);
SmartcardDebug( DEBUG_DRIVER,
("%s!DevicePowerCompletion: called PoSetPowerState with %s\n",DRIVER_NAME,
szDevicePowerState[IrpStack->Parameters.Power.State.DeviceState] ));
PoStartNextPowerIrp(Irp);
// signal that we can process ioctls again
DeviceExtension->lIoCount = 0;
KeSetEvent(&DeviceExtension->ReaderStarted, 0, FALSE);
SmartcardDebug(DEBUG_TRACE,
("%s!DevicePowerCompletion: Exit\n",DRIVER_NAME));
return STATUS_SUCCESS;
}
typedef enum _ACTION {
Undefined = 0,
SkipRequest,
WaitForCompletion,
CompleteRequest,
MarkPending
} ACTION;
/*****************************************************************************
Routine Description:
The power dispatch routine.
This driver is the power policy owner of the device stack,
because this driver knows about the connected reader.
Therefor this driver will translate system power states
to device power states.
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to an I/O Request Packet.
Return Value:
NT NTStatus code
******************************************************************************/
NTSTATUS CMMOB_PowerDeviceControl (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension = &DeviceExtension->SmartcardExtension;
POWER_STATE DesiredPowerState;
KIRQL irql;
ACTION action;
KEVENT event;
SmartcardDebug(DEBUG_TRACE,
( "%s!PowerDeviceControl: Enter\n",DRIVER_NAME));
SmartcardDebug(DEBUG_DRIVER,
( "%s!PowerDeviceControl: IRQL %i\n",DRIVER_NAME,KeGetCurrentIrql()));
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
NTStatus = SmartcardAcquireRemoveLock(SmartcardExtension);
ASSERT(NTStatus == STATUS_SUCCESS);
if (NTStatus!=STATUS_SUCCESS) {
Irp->IoStatus.Status = NTStatus;
Irp->IoStatus.Information = 0;
PoStartNextPowerIrp(Irp);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return NTStatus;
}
ASSERT(SmartcardExtension->ReaderExtension->ReaderPowerState !=
PowerReaderUnspecified);
#ifdef DBG
if (IrpStack->MinorFunction <= IRP_POWER_MN_FUNC_MAX) {
SmartcardDebug(DEBUG_DRIVER,
("%s!PowerDeviceControl: %s received\n",DRIVER_NAME,
szPowerMnFuncDesc[IrpStack->MinorFunction] ));
}
#endif
switch (IrpStack->MinorFunction) {
// ------------------
// IRP_MN_QUERY_POWER
// ------------------
case IRP_MN_QUERY_POWER:
//
// A power policy manager sends this IRP to determine whether it can change
// the system or device power state, typically to go to sleep.
//
switch (IrpStack->Parameters.Power.Type) {
// +++++++++++++++++++
// SystemPowerState
// +++++++++++++++++++
case SystemPowerState:
SmartcardDebug( DEBUG_DRIVER,
("%s!PowerDeviceControl: SystemPowerState = %s\n",DRIVER_NAME,
szSystemPowerState [IrpStack->Parameters.Power.State.SystemState] ));
switch (IrpStack->Parameters.Power.State.SystemState) {
case PowerSystemWorking:
action = SkipRequest;
break;
case PowerSystemSleeping1:
case PowerSystemSleeping2:
case PowerSystemSleeping3:
case PowerSystemHibernate:
KeAcquireSpinLock(&DeviceExtension->SpinLockIoCount, &irql);
if (DeviceExtension->lIoCount == 0) {
// Block any further ioctls
KeClearEvent(&DeviceExtension->ReaderStarted);
action = SkipRequest;
} else {
// can't go to sleep mode since the reader is busy.
NTStatus = STATUS_DEVICE_BUSY;
action = CompleteRequest;
}
KeReleaseSpinLock(&DeviceExtension->SpinLockIoCount, irql);
break;
case PowerSystemShutdown:
action = SkipRequest;
break;
}
break;
// ++++++++++++++++++
// DevicePowerState
// ++++++++++++++++++
case DevicePowerState:
// For requests to D1, D2, or D3 ( sleep or off states ),
// sets DeviceExtension->CurrentDevicePowerState to DeviceState immediately.
// This enables any code checking state to consider us as sleeping or off
// already, as this will imminently become our state.
SmartcardDebug(DEBUG_DRIVER,
("%s!PowerDeviceControl: DevicePowerState = %s\n",DRIVER_NAME,
szDevicePowerState[IrpStack->Parameters.Power.State.DeviceState] ));
action = SkipRequest;
break;
}
break; /* IRP_MN_QUERY_POWER */
// ------------------
// IRP_MN_SET_POWER
// ------------------
case IRP_MN_SET_POWER:
// The system power policy manager sends this IRP to set the system power state.
// A device power policy manager sends this IRP to set the device power state for a device.
// Set Irp->IoStatus.Status to STATUS_SUCCESS to indicate that the device
// has entered the requested state. Drivers cannot fail this IRP.
ASSERT(SmartcardExtension->ReaderExtension->ReaderPowerState != PowerReaderUnspecified);
switch (IrpStack->Parameters.Power.Type) {
// +++++++++++++++++++
// SystemPowerState
// +++++++++++++++++++
case SystemPowerState:
// Get input system power state
SmartcardDebug( DEBUG_DRIVER,
("%s!PowerDeviceControl: SystemPowerState = %s\n",DRIVER_NAME,
szSystemPowerState[IrpStack->Parameters.Power.State.SystemState] ));
// determine desired device powerstate
DesiredPowerState.DeviceState=DeviceExtension->DeviceCapabilities.DeviceState[IrpStack->Parameters.Power.State.SystemState];
SmartcardDebug( DEBUG_DRIVER,
("%s!PowerDeviceControl: DesiredDevicePowerState = %s\n",DRIVER_NAME,
szDevicePowerState[DesiredPowerState.DeviceState] ));
switch (DesiredPowerState.DeviceState) {
case PowerDeviceD0:
if (SmartcardExtension->ReaderExtension->ReaderPowerState == PowerReaderWorking) {
// We're already in the right state
KeSetEvent(&DeviceExtension->ReaderStarted, 0, FALSE);
action = SkipRequest;
break;
}
// wake up the underlying stack...
action = MarkPending;
SmartcardDebug( DEBUG_DRIVER,
("%s!PowerDeviceControl: setting DevicePowerState = %s\n",DRIVER_NAME,
szDevicePowerState[DesiredPowerState.DeviceState] ));
break;
case PowerDeviceD1:
case PowerDeviceD2:
case PowerDeviceD3:
DesiredPowerState.DeviceState = PowerDeviceD3;
if (SmartcardExtension->ReaderExtension->ReaderPowerState == PowerReaderOff) {
// We're already in the right state
KeClearEvent(&DeviceExtension->ReaderStarted);
action = SkipRequest;
break;
}
action = MarkPending;
SmartcardDebug( DEBUG_DRIVER,
("%s!PowerDeviceControl: setting DevicePowerState = %s\n",DRIVER_NAME,
szDevicePowerState[DesiredPowerState.DeviceState] ));
break;
default:
action = SkipRequest;
break;
}
break;
// ++++++++++++++++++
// DevicePowerState
// ++++++++++++++++++
case DevicePowerState:
SmartcardDebug(DEBUG_DRIVER,
("%s!PowerDeviceControl: DevicePowerState = %s\n",DRIVER_NAME,
szDevicePowerState[IrpStack->Parameters.Power.State.DeviceState] ));
switch (IrpStack->Parameters.Power.State.DeviceState) {
case PowerDeviceD0:
// Turn on the reader
SmartcardDebug(DEBUG_DRIVER,
("%s!PowerDeviceControl: PowerDevice D0\n",DRIVER_NAME));
//
// start update thread be signal that it should not run now
// this thread should be started in completion rourine
// but there we have a wrong IRQL for creating a thread
//
KeClearEvent(&DeviceExtension->CanRunUpdateThread);
NTStatus = CMMOB_StartCardTracking(DeviceObject);
if (NTStatus != STATUS_SUCCESS) {
SmartcardDebug(DEBUG_ERROR,
("%s!StartCardTracking failed ! %lx\n",DRIVER_NAME,NTStatus));
}
//
// First, we send down the request to the bus, in order
// to power on the port. When the request completes,
// we turn on the reader
//
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine (Irp,
CMMOB_DevicePowerCompletion,
SmartcardExtension,
TRUE,
TRUE,
TRUE);
action = WaitForCompletion;
break;
case PowerDeviceD1:
case PowerDeviceD2:
case PowerDeviceD3:
// Turn off the reader
SmartcardDebug(DEBUG_DRIVER,
("%s!PowerDeviceControl: PowerDevice D3\n",DRIVER_NAME));
PoSetPowerState (DeviceObject,
DevicePowerState,
IrpStack->Parameters.Power.State);
// Block any further ioctls
KeClearEvent(&DeviceExtension->ReaderStarted);
// stop the update thread
CMMOB_StopCardTracking(DeviceObject);
// save the current card state
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
SmartcardExtension->ReaderExtension->fCardPresent =
SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT;
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
if (SmartcardExtension->ReaderExtension->fCardPresent) {
SmartcardExtension->MinorIoControlCode = SCARD_POWER_DOWN;
NTStatus = CMMOB_PowerOffCard(SmartcardExtension);
ASSERT(NTStatus == STATUS_SUCCESS);
}
// save the current power state of the reader
SmartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderOff;
action = SkipRequest;
break;
default:
action = SkipRequest;
break;
}
break;
} /* case irpStack->Parameters.Power.Type */
break; /* IRP_MN_SET_POWER */
default:
SmartcardDebug(DEBUG_DRIVER,
("%s!PowerDeviceControl: unhandled POWER IRP received\n",DRIVER_NAME));
//
// All unhandled power messages are passed on to the PDO
//
action = SkipRequest;
break;
} /* irpStack->MinorFunction */
switch (action) {
case CompleteRequest:
SmartcardReleaseRemoveLock(SmartcardExtension);
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = NTStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
case MarkPending:
// initialize the event we need in the completion function
KeInitializeEvent(&event,
NotificationEvent,
FALSE);
// request the device power irp
NTStatus = PoRequestPowerIrp (DeviceObject,
IRP_MN_SET_POWER,
DesiredPowerState,
CMMOB_SystemPowerCompletion,
&event,
NULL);
SmartcardDebug( DEBUG_DRIVER,
("%s!PowerDeviceControl: called PoRequestPowerIrp with %s\n",DRIVER_NAME,
szDevicePowerState[DesiredPowerState.DeviceState] ));
ASSERT(NTStatus == STATUS_PENDING);
if (NTStatus == STATUS_PENDING) {
// wait until the device power irp completed
NTStatus = KeWaitForSingleObject(&event,
Executive,
KernelMode,
FALSE,
NULL);
}
if (NTStatus == STATUS_SUCCESS) {
SmartcardReleaseRemoveLock(SmartcardExtension);
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
NTStatus = PoCallDriver(DeviceExtension->AttachedDeviceObject, Irp);
} else {
SmartcardReleaseRemoveLock(SmartcardExtension);
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = NTStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
break;
case SkipRequest:
SmartcardReleaseRemoveLock(SmartcardExtension);
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
NTStatus = PoCallDriver(DeviceExtension->AttachedDeviceObject, Irp);
break;
case WaitForCompletion:
NTStatus = PoCallDriver(DeviceExtension->AttachedDeviceObject, Irp);
break;
default:
SmartcardReleaseRemoveLock(SmartcardExtension);
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
NTStatus = PoCallDriver(DeviceExtension->AttachedDeviceObject, Irp);
break;
}
SmartcardDebug(DEBUG_TRACE,
("%s!PowerDeviceControl: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
* History:
* $Log: cmbp0pnp.c $
* Revision 1.4 2000/08/24 09:05:12 TBruendl
* No comment given
*
* Revision 1.3 2000/07/27 13:53:01 WFrischauf
* No comment given
*
*
******************************************************************************/