You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1012 lines
36 KiB
1012 lines
36 KiB
/*****************************************************************************
|
|
@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
|
|
*
|
|
*
|
|
******************************************************************************/
|
|
|