Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2816 lines
94 KiB

/*++
Copyright (c) 1998 Gemplus Development
Name:
Gprnt.C
Description:
This is the main module which holds:
- the main functions for a standard DDK NT driver
- the IOCTL functions defined for this driver.
Environment:
Kernel Mode
Revision History:
08/10/99: Y. Nadeau
- Make a version for Compaq PC-CARD Reader.
06/04/98: (Y. Nadeau M. Veillette)
- Code review
18/11/98: V1.00.006 (Y. Nadeau)
- Add log errors at startup, and Cleanup revised.
16/10/98: V1.00.005 (Y. Nadeau)
- Remove DEVICEID in IoCreateDevice (Klaus)
18/09/98: V1.00.004 (Y. Nadeau)
- Correction for NT5 beta 3
06/05/98: V1.00.003 (P. Plouidy)
- Power management for NT5
10/02/98: V1.00.002 (P. Plouidy)
- Plug and Play for NT5
03/07/97: V1.00.001 (P. Plouidy)
- Start of development.
--*/
#include <stdio.h>
#include "gprnt.h"
#include "gprcmd.h"
#include "gprelcmd.h"
#include "logmsg.h"
//
// Pragma section
//
#pragma alloc_text (INIT,DriverEntry)
#pragma alloc_text (PAGEABLE,GprAddDevice)
#pragma alloc_text (PAGEABLE,GprCreateDevice)
#pragma alloc_text (PAGEABLE,GprUnloadDevice)
#pragma alloc_text (PAGEABLE,GprUnloadDriver)
#if DBG
#pragma optimize ("",off)
#endif
//
// Constant section
// - MAX_DEVICES is the maximum number of device supported
// - POLLING_TIME polling frequency in ms
//
#define MAX_DEVICES 4
#define POLLING_TIME 500
ULONG dataRatesSupported[] = {9909};
//
// Global variable section
// bDeviceSlot is an array of boolean to signal if a device is already created.
//
BOOLEAN bDeviceSlot[GPR_MAX_DEVICE];
NTSTATUS DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
)
/*++
Routine description:
This routine is called at system initialization time to initialize
this driver.
Arguments
DriverObject - supplies the driver object.
RegistryPath - supplies the registry path for this driver.
Return Value:
STATUS_SUCCESS We could initialize at least one device
--*/
{
SmartcardDebug(
DEBUG_INFO,
("%s!DriverEntry: Enter - %s %s\n",
SC_DRIVER_NAME,
__DATE__,
__TIME__)
);
// Initialization of the Driver Object with driver's entry points.
DriverObject->DriverUnload = GprUnloadDriver;
DriverObject->DriverExtension->AddDevice = GprAddDevice;
DriverObject->MajorFunction[IRP_MJ_PNP] = GprDispatchPnp;
DriverObject->MajorFunction[IRP_MJ_CREATE] = GprCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = GprCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = GprCleanup;
DriverObject->MajorFunction[IRP_MJ_POWER] = GprPower;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = GprDeviceControl;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = GprSystemControl;
SmartcardDebug(
DEBUG_DRIVER,
("%s!DriverEntry: Exit\n",
SC_DRIVER_NAME)
);
return(STATUS_SUCCESS);
}
NTSTATUS GprAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
Add device routine
Arguments
DriverObject point to the driver object.
PhysicalDeviceObject point to the PDO for the pnp device added
Return Value:
STATUS_SUCCESS
STATUS_INSUFFICIENT_RESOURCES
*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PDEVICE_OBJECT DeviceObject = NULL;
ANSI_STRING DeviceID;
PAGED_CODE();
ASSERT(DriverObject != NULL);
ASSERT(PhysicalDeviceObject != NULL);
SmartcardDebug(
DEBUG_DRIVER,
( "%s!GprAddDevice: Enter\n",
SC_DRIVER_NAME)
);
__try
{
PDEVICE_EXTENSION DeviceExtension;
LONG DeviceIdLength;
//
// try to create the device
//
NTStatus = GprCreateDevice(
DriverObject,
PhysicalDeviceObject,
&DeviceObject
);
if (NTStatus != STATUS_SUCCESS) {
SmartcardDebug(
DEBUG_ERROR,
( "%s!GprAddDevice: GprCreateDevice=%X(hex)\n",
SC_DRIVER_NAME,
NTStatus)
);
__leave;
}
//
// Attach the physicalDeviceObject to the new created device
//
DeviceExtension = DeviceObject->DeviceExtension;
DeviceExtension->SmartcardExtension.ReaderExtension->AttachedDeviceObject = IoAttachDeviceToDeviceStack(
DeviceObject,
PhysicalDeviceObject
);
ASSERT(DeviceExtension->SmartcardExtension.ReaderExtension->AttachedDeviceObject != NULL);
if (DeviceExtension->SmartcardExtension.ReaderExtension->AttachedDeviceObject == NULL) {
NTStatus = STATUS_UNSUCCESSFUL;
__leave;
}
//
// Register the new device object
//
NTStatus = IoRegisterDeviceInterface(
PhysicalDeviceObject,
&SmartCardReaderGuid,
NULL,
&DeviceExtension->PnPDeviceName
);
RtlUnicodeStringToAnsiString(&DeviceID, &DeviceExtension->PnPDeviceName, TRUE);
DeviceIdLength = (LONG) RtlCompareMemory(DeviceID.Buffer, COMPAQ_ID, CHECK_ID_LEN);
SmartcardDebug(
DEBUG_ERROR,
( "%s!GprAddDevice: DeviceIdLength = %d, PnPDeviceName=%s\n",
SC_DRIVER_NAME, DeviceIdLength, DeviceID.Buffer)
);
// it's a DeviceID of COMPAQ ?
if ( DeviceIdLength == CHECK_ID_LEN) {
SmartcardDebug(
DEBUG_INFO,
( "%s!GprAddDevice: Compaq reader detect!\n",
SC_DRIVER_NAME)
);
DeviceExtension->DriverFlavor = DF_CPQ400;
}
// Initialize the vendor information.
// Driver flavor
//
switch (DeviceExtension->DriverFlavor) {
case DF_IBM400:
// IBM IBM400
RtlCopyMemory(DeviceExtension->SmartcardExtension.VendorAttr.VendorName.Buffer,
SZ_VENDOR_NAME_IBM, sizeof(SZ_VENDOR_NAME_IBM));
RtlCopyMemory(DeviceExtension->SmartcardExtension.VendorAttr.IfdType.Buffer,
SZ_READER_NAME_IBM, sizeof(SZ_READER_NAME_IBM));
DeviceExtension->SmartcardExtension.VendorAttr.VendorName.Length = sizeof(SZ_VENDOR_NAME_IBM);
DeviceExtension->SmartcardExtension.VendorAttr.IfdType.Length = sizeof(SZ_READER_NAME_IBM);
break;
case DF_CPQ400:
// COMPAQ PC_CARD_SMARTCARD_READER
RtlCopyMemory(DeviceExtension->SmartcardExtension.VendorAttr.VendorName.Buffer,
SZ_VENDOR_NAME_COMPAQ, sizeof(SZ_VENDOR_NAME_COMPAQ));
RtlCopyMemory(DeviceExtension->SmartcardExtension.VendorAttr.IfdType.Buffer,
SZ_READER_NAME_COMPAQ, sizeof(SZ_READER_NAME_COMPAQ));
DeviceExtension->SmartcardExtension.VendorAttr.VendorName.Length = sizeof(SZ_VENDOR_NAME_COMPAQ);
DeviceExtension->SmartcardExtension.VendorAttr.IfdType.Length = sizeof(SZ_READER_NAME_COMPAQ);
break;
default:
// Gemplus GPR400
break;
}
SmartcardDebug(
DEBUG_INFO,
( "%s!GprAddDevice: DriverFlavor VendorName:%s IfdType:%s UnitNo:%d\n",
SC_DRIVER_NAME,
DeviceExtension->SmartcardExtension.VendorAttr.VendorName.Buffer,
DeviceExtension->SmartcardExtension.VendorAttr.IfdType.Buffer,
DeviceExtension->SmartcardExtension.VendorAttr.UnitNo)
);
RtlFreeAnsiString(&DeviceID);
ASSERT(NTStatus == STATUS_SUCCESS);
DeviceObject->Flags |= DO_BUFFERED_IO;
DeviceObject->Flags |= DO_POWER_PAGABLE;
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
}
__finally
{
if (NTStatus != STATUS_SUCCESS) {
GprUnloadDevice(DeviceObject);
}
}
SmartcardDebug(
DEBUG_DRIVER,
( "%s!GprAddDevice: Exit =%X(hex)\n",
SC_DRIVER_NAME,
NTStatus)
);
return NTStatus;
}
NTSTATUS GprCreateDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject,
OUT PDEVICE_OBJECT *DeviceObject
)
/*++
Routine description:
This routine creates an object for the physical device specified
and sets up the deviceExtension
Arguments:
DriverObject context of call
DeviceObject ptr to the created device object
Return value:
STATUS_SUCCESS
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
ULONG DeviceInstance;
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
PAGED_CODE();
ASSERT(DriverObject != NULL);
ASSERT(PhysicalDeviceObject != NULL);
*DeviceObject = NULL;
SmartcardDebug(
DEBUG_DRIVER,
( "%s!GprCreateDevice: Enter\n",
SC_DRIVER_NAME)
);
__try
{
for ( DeviceInstance = 0; DeviceInstance < GPR_MAX_DEVICE; DeviceInstance++ ) {
if (bDeviceSlot[DeviceInstance] == FALSE) {
bDeviceSlot[DeviceInstance] = TRUE;
break;
}
}
// Create the device object
NTStatus = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION),
NULL,
FILE_DEVICE_SMARTCARD,
0,
TRUE,
DeviceObject
);
if (NTStatus != STATUS_SUCCESS) {
SmartcardDebug(
DEBUG_ERROR,
( "%s!GprCreateDevice: IoCreateDevice status=%X(hex)\n",
SC_DRIVER_NAME,
NTStatus)
);
SmartcardLogError(
DriverObject,
GEMSCR0D_ERROR_CLAIM_RESOURCES,
NULL,
0
);
__leave;
}
ASSERT(DeviceObject != NULL);
// set up the device extension.
DeviceExtension = (*DeviceObject)->DeviceExtension;
ASSERT(DeviceExtension != NULL);
SmartcardExtension = &DeviceExtension->SmartcardExtension;
// allocate the reader extension
SmartcardExtension->ReaderExtension = ExAllocatePool(
NonPagedPool,
sizeof( READER_EXTENSION )
);
if ( SmartcardExtension->ReaderExtension == NULL ) {
SmartcardLogError(
DriverObject,
GEMSCR0D_ERROR_CLAIM_RESOURCES,
NULL,
0
);
SmartcardDebug(
DEBUG_ERROR,
( "%s!GprCreateDevice: ReaderExtension failed %X(hex)\n",
SC_DRIVER_NAME,
NTStatus )
);
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
RtlZeroMemory(
SmartcardExtension->ReaderExtension,
sizeof( READER_EXTENSION )
);
// allocate the Vo Buffer
SmartcardExtension->ReaderExtension->Vo = ExAllocatePool(
NonPagedPool,
GPR_BUFFER_SIZE
);
if ( SmartcardExtension->ReaderExtension->Vo == NULL ) {
SmartcardLogError(
DriverObject,
GEMSCR0D_ERROR_CLAIM_RESOURCES,
NULL,
0
);
SmartcardDebug(
DEBUG_ERROR,
( "%s!GprCreateDevice: Vo buffer failed %X(hex)\n",
SC_DRIVER_NAME,
NTStatus )
);
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
RtlZeroMemory(
SmartcardExtension->ReaderExtension->Vo,
GPR_BUFFER_SIZE
);
// Used for device removal notification
KeInitializeEvent(
&(SmartcardExtension->ReaderExtension->ReaderRemoved),
NotificationEvent,
FALSE
);
//
// GPR400 acknowledge event initialization
//
KeInitializeEvent(
&(SmartcardExtension->ReaderExtension->GPRAckEvent),
SynchronizationEvent,
FALSE
);
KeInitializeEvent(
&(SmartcardExtension->ReaderExtension->GPRIccPresEvent),
SynchronizationEvent,
FALSE
);
// Setup the DPC routine to be called after the ISR completes.
KeInitializeDpc(
&DeviceExtension->DpcObject,
GprCardEventDpc,
*DeviceObject // should be DeviceExtension
);
// Card presence polling DPC routine initialization
KeInitializeDpc(
&SmartcardExtension->ReaderExtension->CardDpcObject,
GprCardPresenceDpc,
DeviceExtension
);
// Initialization of the card detection timer
KeInitializeTimer(
&(SmartcardExtension->ReaderExtension->CardDetectionTimer)
);
// This event signals Start/Stop notification
KeInitializeEvent(
&DeviceExtension->ReaderStarted,
NotificationEvent,
FALSE
);
// Used to keep track of open calls
KeInitializeEvent(
&DeviceExtension->ReaderClosed,
NotificationEvent,
TRUE
);
// Used to keep track of open calls
KeInitializeEvent(
&SmartcardExtension->ReaderExtension->IdleState,
SynchronizationEvent,
TRUE
);
SmartcardExtension->ReaderExtension->RestartCardDetection = FALSE;
// void function, This routine must be called
// before an initial call to KeAcquireSpinLock
KeInitializeSpinLock(&DeviceExtension->SpinLock);
// This worker thread is use to start de GPR in Power mode
DeviceExtension->GprWorkStartup = IoAllocateWorkItem(
*DeviceObject
);
if ( DeviceExtension->GprWorkStartup == NULL ) {
SmartcardLogError(
DriverObject,
GEMSCR0D_ERROR_CLAIM_RESOURCES,
NULL,
0
);
SmartcardDebug(
DEBUG_ERROR,
( "%s!GprCreateDevice: GprWorkStartup failed %X(hex)\n",
SC_DRIVER_NAME,
NTStatus )
);
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
// Now setup information in our deviceExtension.
SmartcardExtension->ReaderCapabilities.CurrentState = (ULONG) SCARD_UNKNOWN;
SmartcardExtension->ReaderCapabilities.MechProperties = 0;
// enter correct version of the lib
SmartcardExtension->Version = SMCLIB_VERSION;
// Setup the Smartcard support functions that we implement.
SmartcardExtension->ReaderFunction[RDF_CARD_POWER] = GprCbReaderPower;
SmartcardExtension->ReaderFunction[RDF_TRANSMIT] = GprCbTransmit;
SmartcardExtension->ReaderFunction[RDF_SET_PROTOCOL] = GprCbSetProtocol;
SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING] = GprCbSetupCardTracking;
SmartcardExtension->ReaderFunction[RDF_IOCTL_VENDOR] = GprCbVendorIoctl;
DeviceExtension->PowerState = PowerDeviceD0;
// Initialize the vendor information.
strcpy(SmartcardExtension->VendorAttr.VendorName.Buffer, SC_VENDOR_NAME);
strcpy(SmartcardExtension->VendorAttr.IfdType.Buffer, SC_IFD_TYPE);
SmartcardExtension->VendorAttr.VendorName.Length = (USHORT)strlen(SC_VENDOR_NAME);
SmartcardExtension->VendorAttr.IfdType.Length = (USHORT)strlen(SC_IFD_TYPE);
SmartcardExtension->VendorAttr.UnitNo = DeviceInstance;
DeviceExtension->DriverFlavor = DF_GPR400;
//
// Reader capabilities:
// - the type of the reader (SCARD_READER_TYPE_PCMCIA)
// - the protocols supported by the reader (SCARD_PROTOCOL_T0, SCARD_PROTOCOL_T1)
// - the mechanical characteristic of the reader:
// Verify if the reader can supports the detection of the card
// insertion/removal. Only the main reader supports this functionnality.
// - the default clock frequency
// - the maximum clock frequency
// - the default data rate
// - the maximum data rate
// - the maximum IFSD
//
SmartcardExtension->ReaderCapabilities.ReaderType =
SCARD_READER_TYPE_PCMCIA;
SmartcardExtension->ReaderCapabilities.SupportedProtocols =
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
SmartcardExtension->ReaderCapabilities.Channel = DeviceInstance;
SmartcardExtension->ReaderCapabilities.CLKFrequency.Default = GPR_DEFAULT_FREQUENCY;
SmartcardExtension->ReaderCapabilities.CLKFrequency.Max = GPR_MAX_FREQUENCY;
SmartcardExtension->ReaderCapabilities.MaxIFSD = GPR_MAX_IFSD;
SmartcardExtension->ReaderCapabilities.DataRate.Default = GPR_DEFAULT_DATARATE;
SmartcardExtension->ReaderCapabilities.DataRate.Max = GPR_MAX_DATARATE;
//
// Reader capabilities (continue):
// - List all the supported data rates
//
SmartcardExtension->ReaderCapabilities.DataRatesSupported.List =
dataRatesSupported;
SmartcardExtension->ReaderCapabilities.DataRatesSupported.Entries =
sizeof(dataRatesSupported) / sizeof(dataRatesSupported[0]);
//
// Reader Extension:
//- the command timeout for the reader (GPR_DEFAULT_TIME)
//
SmartcardExtension->ReaderExtension->CmdTimeOut = GPR_DEFAULT_TIME;
SmartcardExtension->ReaderExtension->PowerTimeOut = GPR_DEFAULT_POWER_TIME;
//
// Flag will prevent completion of the request
// when the system will be waked up again.
//
SmartcardExtension->ReaderExtension->PowerRequest = FALSE;
//
// Flag to know we strating a new device, not an hibernation mode.
//
SmartcardExtension->ReaderExtension->NewDevice = TRUE;
SmartcardExtension->SmartcardRequest.BufferSize = MIN_BUFFER_SIZE;
SmartcardExtension->SmartcardReply.BufferSize = MIN_BUFFER_SIZE;
NTStatus = SmartcardInitialize(SmartcardExtension);
if (NTStatus != STATUS_SUCCESS) {
SmartcardLogError(
DriverObject,
GEMSCR0D_ERROR_CLAIM_RESOURCES,
NULL,
0
);
SmartcardDebug(
DEBUG_ERROR,
( "%s!GprCreateDevice: SmartcardInitialize failed %X(hex)\n",
SC_DRIVER_NAME,
NTStatus )
);
__leave;
}
//
// tell the lib our device object & create
// symbolic link
//
SmartcardExtension->OsData->DeviceObject = *DeviceObject;
// save the current power state of the reader
SmartcardExtension->ReaderExtension->ReaderPowerState =
PowerReaderWorking;
}
__finally
{
if (NTStatus != STATUS_SUCCESS) {
// Do the driver unload in the calling function.
}
SmartcardDebug(
DEBUG_DRIVER,
( "%s!GprCreateDevice: Exit %X(hex)\n",
SC_DRIVER_NAME,
NTStatus )
);
}
return NTStatus;
}
NTSTATUS GprStartDevice(
PDEVICE_OBJECT DeviceObject,
PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor
)
/*++
Routine Description
get the actual configuration from the passed FullResourceDescriptor
and initializes the reader hardware
--*/
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION pSCardExt = &DeviceExtension->SmartcardExtension;
PREADER_EXTENSION pReaderExt = pSCardExt->ReaderExtension;
NTSTATUS NTStatus = STATUS_SUCCESS;
ULONG Count;
PCMCIA_READER_CONFIG *pConfig = NULL;
ASSERT(DeviceObject != NULL);
ASSERT(FullResourceDescriptor != NULL);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprStartDevice: Enter \n",
SC_DRIVER_NAME)
);
// Get the number of resources we need
Count = FullResourceDescriptor->PartialResourceList.Count;
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprStartDevice: Resource Count = %d\n",
SC_DRIVER_NAME,
Count)
);
PartialDescriptor = FullResourceDescriptor->PartialResourceList.PartialDescriptors;
pConfig = &(pReaderExt->ConfigData);
//
// parse all partial descriptors
//
while (Count--) {
switch (PartialDescriptor->Type) {
case CmResourceTypePort:
{
//
// 0 - memory, 1 - IO
//
ULONG AddressSpace = 1;
pReaderExt->BaseIoAddress =
(PGPR400_REGISTERS) UlongToPtr(PartialDescriptor->u.Port.Start.LowPart);
ASSERT(PartialDescriptor->u.Port.Length >= 4);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprStartDevice: IoBase = %lxh\n",
SC_DRIVER_NAME,
pReaderExt->BaseIoAddress)
);
break;
}
case CmResourceTypeInterrupt:
{
KINTERRUPT_MODE Mode;
BOOLEAN Shared;
Mode = (
PartialDescriptor->Flags &
CM_RESOURCE_INTERRUPT_LATCHED ?
Latched : LevelSensitive
);
Shared = (
PartialDescriptor->ShareDisposition ==
CmResourceShareShared
);
pConfig->Vector = PartialDescriptor->u.Interrupt.Vector;
pConfig->Affinity = PartialDescriptor->u.Interrupt.Affinity;
pConfig->Level = (KIRQL) PartialDescriptor->u.Interrupt.Level;
//
// store IRQ to allow query configuration
//
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprStartDevice: Irq Vector: %d\n",
SC_DRIVER_NAME,
PartialDescriptor->u.Interrupt.Vector)
);
DeviceExtension->InterruptServiceRoutine = GprIsr;
DeviceExtension->IsrContext = DeviceExtension;
//
//connect the driver's isr
//
NTStatus = IoConnectInterrupt(
&DeviceExtension->InterruptObject,
DeviceExtension->InterruptServiceRoutine,
DeviceExtension->IsrContext,
NULL,
pConfig->Vector,
pConfig->Level,
pConfig->Level,
Mode,
Shared,
pConfig->Affinity,
FALSE
);
break;
}
default:
NTStatus = STATUS_UNSUCCESSFUL;
break;
}
PartialDescriptor++;
}
__try
{
//
// IOBase initialized ?
//
if ( pReaderExt->BaseIoAddress == NULL ) {
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprStartDevice: No IO \n",
SC_DRIVER_NAME)
);
//
// under NT 4.0 the failure of this fct for the second reader
// means there is only one device
//
SmartcardLogError(
DeviceObject,
GEMSCR0D_ERROR_IO_PORT,
NULL,
0
);
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
//
// irq connected ?
//
if ( DeviceExtension->InterruptObject == NULL ) {
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprStartDevice: No Irq \n",
SC_DRIVER_NAME)
);
SmartcardLogError(
DeviceObject,
GEMSCR0D_ERROR_INTERRUPT,
NULL,
0
);
NTStatus = STATUS_INSUFFICIENT_RESOURCES;
__leave;
}
// YN
//
// GPR400 Check Hardware
//
NTStatus = IfdCheck(pSCardExt);
if (NTStatus != STATUS_SUCCESS) {
SmartcardDebug(
DEBUG_INFO,
("%s!GprStartDevice: ####### Reader is at bad state...\n",
SC_DRIVER_NAME)
);
SmartcardLogError(
DeviceObject,
GEMSCR0D_UNABLE_TO_INITIALIZE,
NULL,
0
);
// Unblock reader
KeClearEvent(&pReaderExt->ReaderRemoved);
KeSetEvent(&DeviceExtension->ReaderStarted, 0, FALSE);
__leave;
}
// StartGpr in a worker thread.
IoQueueWorkItem(
DeviceExtension->GprWorkStartup,
(PIO_WORKITEM_ROUTINE) GprWorkStartup,
DelayedWorkQueue,
NULL
);
//
// Put interface here
//
NTStatus = IoSetDeviceInterfaceState(
&DeviceExtension->PnPDeviceName,
TRUE
);
}
__finally
{
if (!NT_SUCCESS(NTStatus)) {
DeviceExtension->OpenFlag = FALSE;
GprStopDevice(DeviceObject);
}
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprStartDevice: Exit %X(hex)\n",
SC_DRIVER_NAME,
NTStatus)
);
}
return NTStatus;
}
VOID GprStopDevice(
PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description
Disconnect the interrupt used by the device & unmap the IO port
--*/
{
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION pSCardExt = NULL;
ASSERT(DeviceObject != NULL);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprStopDevice: Enter \n",
SC_DRIVER_NAME)
);
DeviceExtension = DeviceObject->DeviceExtension;
pSCardExt = &(DeviceExtension->SmartcardExtension);
//
// disconnect the interrupt
//
if ( DeviceExtension->InterruptObject != NULL ) {
IoDisconnectInterrupt(DeviceExtension->InterruptObject);
DeviceExtension->InterruptObject = NULL;
}
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprStopDevice: Exit \n",
SC_DRIVER_NAME)
);
}
NTSTATUS
GprSystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
DeviceObject - Pointer to device object for this miniport
Irp - IRP involved.
Return Value:
STATUS_SUCCESS.
--*/
{
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
PREADER_EXTENSION ReaderExtension;
NTSTATUS status = STATUS_SUCCESS;
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
ReaderExtension = SmartcardExtension->ReaderExtension;
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(ReaderExtension->AttachedDeviceObject, Irp);
return status;
}
NTSTATUS GprDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine description
this is the IOCTL dispatch function
--*/
{
PDEVICE_EXTENSION DeviceExtension = NULL;
PSMARTCARD_EXTENSION SmartcardExtension = NULL;
NTSTATUS NTStatus = STATUS_SUCCESS;
LARGE_INTEGER Timeout;
KIRQL irql;
ASSERT(DeviceObject != NULL);
ASSERT(Irp != NULL);
DeviceExtension = DeviceObject->DeviceExtension;
ASSERT(DeviceExtension != NULL);
SmartcardExtension = &(DeviceExtension->SmartcardExtension);
ASSERT(SmartcardExtension != NULL);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDeviceControl: Enter\n",SC_DRIVER_NAME));
KeAcquireSpinLock(&DeviceExtension->SpinLock,&irql);
if (DeviceExtension->IoCount == 0) {
KeReleaseSpinLock(&DeviceExtension->SpinLock,irql);
NTStatus = KeWaitForSingleObject(
&DeviceExtension->ReaderStarted,
Executive,
KernelMode,
FALSE,
NULL);
ASSERT(NTStatus == STATUS_SUCCESS);
KeAcquireSpinLock(&DeviceExtension->SpinLock,&irql);
}
ASSERT(DeviceExtension->IoCount >= 0);
DeviceExtension->IoCount++;
KeReleaseSpinLock(&DeviceExtension->SpinLock,irql);
Timeout.QuadPart = 0;
NTStatus = KeWaitForSingleObject(
&(SmartcardExtension->ReaderExtension->ReaderRemoved),
Executive,
KernelMode,
FALSE,
&Timeout
);
if (NTStatus == STATUS_SUCCESS) {
NTStatus = STATUS_DEVICE_REMOVED;
} else {
NTStatus = SmartcardAcquireRemoveLockWithTag(SmartcardExtension, 'tcoI');
// Cancel the card detection timer
KeCancelTimer(&(DeviceExtension->SmartcardExtension.ReaderExtension->CardDetectionTimer));
AskForCardPresence(SmartcardExtension);
Timeout.QuadPart = -(100 * POLLING_TIME);
KeWaitForSingleObject(
&(DeviceExtension->SmartcardExtension.ReaderExtension->GPRIccPresEvent),
Executive,
KernelMode,
FALSE,
&Timeout
);
}
if (NTStatus != STATUS_SUCCESS) {
// The device has been removed. Fail the call
KeAcquireSpinLock(&DeviceExtension->SpinLock,&irql);
DeviceExtension->IoCount--;
KeReleaseSpinLock(&DeviceExtension->SpinLock,irql);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_DEVICE_REMOVED;
NTStatus = STATUS_DEVICE_REMOVED;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDeviceControl: Exit %x\n"
,SC_DRIVER_NAME
,NTStatus)
);
return(STATUS_DEVICE_REMOVED);
}
ASSERT(DeviceExtension->SmartcardExtension.ReaderExtension->ReaderPowerState ==
PowerReaderWorking);
NTStatus = SmartcardDeviceControl(
&DeviceExtension->SmartcardExtension,
Irp
);
// Restart the card detection timer
Timeout.QuadPart = -(10000 * POLLING_TIME);
KeSetTimer(
&(SmartcardExtension->ReaderExtension->CardDetectionTimer),
Timeout,
&SmartcardExtension->ReaderExtension->CardDpcObject
);
//SmartcardReleaseRemoveLock(SmartcardExtension);
SmartcardReleaseRemoveLockWithTag(SmartcardExtension, 'tcoI');
KeAcquireSpinLock(&DeviceExtension->SpinLock,&irql);
DeviceExtension->IoCount--;
ASSERT(DeviceExtension->IoCount >= 0);
KeReleaseSpinLock(&DeviceExtension->SpinLock,irql);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDeviceControl: Exit %x\n"
,SC_DRIVER_NAME
,NTStatus)
);
return(NTStatus);
}
VOID GprFinishPendingRequest(
PDEVICE_OBJECT DeviceObject,
NTSTATUS NTStatus
)
/*++
Routine Description :
finishes a pending tracking request if the interrupt is served or the device
will be unloaded
Arguments
DeviceObject context of the request
NTStatus status to report to the calling process
Return Value
STATUS_SUCCESS
--*/
{
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
KIRQL CurrentIrql;
PIRP PendingIrp;
ASSERT(DeviceObject != NULL);
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
if ( SmartcardExtension->OsData->NotificationIrp != NULL ) {
SmartcardDebug(
DEBUG_DRIVER,
( "%s!GprFinishPendingRequest: Completing Irp %lx\n",
SC_DRIVER_NAME,
SmartcardExtension->OsData->NotificationIrp)
);
PendingIrp = SmartcardExtension->OsData->NotificationIrp;
IoAcquireCancelSpinLock( &CurrentIrql );
IoSetCancelRoutine( PendingIrp, NULL );
IoReleaseCancelSpinLock( CurrentIrql );
//
// finish the request
//
PendingIrp->IoStatus.Status = NTStatus;
PendingIrp->IoStatus.Information = 0;
IoCompleteRequest(PendingIrp, IO_NO_INCREMENT );
//
// reset the tracking context to enable tracking
//
SmartcardExtension->OsData->NotificationIrp = NULL;
}
}
NTSTATUS GprCallPcmciaDriver(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
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
status returned by the pcmcia driver
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
KEVENT Event;
ASSERT(DeviceObject != NULL);
ASSERT(Irp != NULL);
// Copy our stack location to the next.
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// 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,
GprComplete,
&Event,
TRUE,
TRUE,
TRUE
);
//
// Call the pcmcia driver
//
if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_POWER) {
NTStatus = PoCallDriver(
DeviceExtension->SmartcardExtension.ReaderExtension->AttachedDeviceObject,
Irp
);
} else {
NTStatus = IoCallDriver(
DeviceExtension->SmartcardExtension.ReaderExtension->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_DRIVER,
("%s!GprCallPcmciaDriver: Exit %x\n",
SC_DRIVER_NAME,
NTStatus)
);
return NTStatus;
}
NTSTATUS GprComplete (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PKEVENT Event
)
/*++
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 GprCallPcmciaDriver can continue.
Arguments:
DeviceObject context of call
Irp Irp to complete
Event Used by GprCallPcmciaDriver 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
GprCallPcmciaDriver
--*/
{
UNREFERENCED_PARAMETER (DeviceObject);
ASSERT(Irp != NULL);
ASSERT(Event != NULL);
if (Irp->Cancel) {
Irp->IoStatus.Status = STATUS_CANCELLED;
}
// else
// {
// Irp->IoStatus.Status = STATUS_MORE_PROCESSING_REQUIRED;
// }
KeSetEvent (Event, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS GprDispatchPnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
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
status returned by pcmcia driver
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION smartcardExtension = NULL;
PIO_STACK_LOCATION IrpStack;
BOOLEAN deviceRemoved = FALSE, irpSkipped = FALSE;
KIRQL irql;
LARGE_INTEGER Timeout;
ASSERT(DeviceObject != NULL);
ASSERT(Irp != NULL);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDispatchPnp: Enter\n",
SC_DRIVER_NAME)
);
smartcardExtension = &(DeviceExtension->SmartcardExtension);
//NTStatus = SmartcardAcquireRemoveLock(smartcardExtension);
NTStatus = SmartcardAcquireRemoveLockWithTag(smartcardExtension, ' PnP');
ASSERT(NTStatus == STATUS_SUCCESS);
if (NTStatus != STATUS_SUCCESS) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = NTStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return NTStatus;
}
// Irp->IoStatus.Information = 0;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
Timeout.QuadPart = 0;
//
// Now look what the PnP manager wants...
//
switch (IrpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
//
// Now we should connect to our resources (Irql, Io etc.)
//
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDispatchPnp: IRP_MN_START_DEVICE\n",
SC_DRIVER_NAME)
);
//
// We have to call the underlying driver first
//
NTStatus = GprCallPcmciaDriver(
DeviceObject,
Irp
);
ASSERT(NT_SUCCESS(NTStatus));
if (NT_SUCCESS(NTStatus)) {
NTStatus = GprStartDevice(
DeviceObject,
&IrpStack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0]
);
}
break;
case IRP_MN_QUERY_STOP_DEVICE:
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDispatchPnP: IRP_MN_QUERY_STOP_DEVICE\n",
SC_DRIVER_NAME)
);
KeAcquireSpinLock(&DeviceExtension->SpinLock, &irql);
if (DeviceExtension->IoCount > 0) {
// we refuse to stop if we have pending io
KeReleaseSpinLock(&DeviceExtension->SpinLock, irql);
NTStatus = STATUS_DEVICE_BUSY;
} else {
// stop processing requests
KeClearEvent(&DeviceExtension->ReaderStarted);
KeReleaseSpinLock(&DeviceExtension->SpinLock, irql);
NTStatus = GprCallPcmciaDriver(
DeviceObject,
Irp);
}
break;
case IRP_MN_CANCEL_STOP_DEVICE:
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDispatchPnP: IRP_MN_CANCEL_STOP_DEVICE\n",
SC_DRIVER_NAME)
);
NTStatus = GprCallPcmciaDriver(
DeviceObject,
Irp
);
if (NTStatus == STATUS_SUCCESS) {
// we can continue to process requests
KeSetEvent(&DeviceExtension->ReaderStarted, 0, FALSE);
}
break;
case IRP_MN_STOP_DEVICE:
//
// Stop the device.
//
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDispatchPnp: IRP_MN_STOP_DEVICE\n",
SC_DRIVER_NAME)
);
GprStopDevice(DeviceObject);
NTStatus = GprCallPcmciaDriver(DeviceObject, Irp);
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
//
// Remove our device
//
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDispatchPnp: IRP_MN_QUERY_REMOVE_DEVICE\n",
SC_DRIVER_NAME)
);
// disable the reader
NTStatus = IoSetDeviceInterfaceState(
&DeviceExtension->PnPDeviceName,
FALSE
);
SmartcardDebug(
DEBUG_TRACE,
("%s!GprDispatchPnp: Set Pnp Interface state to FALSE, status=%x\n",
SC_DRIVER_NAME,
NTStatus)
);
if (NTStatus != STATUS_SUCCESS) {
break;
}
//
// check if the reader has been opened
// Note: This call only checks and does NOT wait for a close
//
Timeout.QuadPart = 0;
NTStatus = KeWaitForSingleObject(
&DeviceExtension->ReaderClosed,
Executive,
KernelMode,
FALSE,
&Timeout
);
if (NTStatus == STATUS_TIMEOUT) {
// someone is connected, enable the reader and fail the call
IoSetDeviceInterfaceState(
&DeviceExtension->PnPDeviceName,
TRUE
);
SmartcardDebug(
DEBUG_TRACE,
("%s!GprDispatchPnp: Set Pnp Interface state to TRUE\n",
SC_DRIVER_NAME)
);
NTStatus = STATUS_UNSUCCESSFUL;
break;
}
// pass the call to the next driver in the stack
NTStatus = GprCallPcmciaDriver(DeviceObject, Irp);
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
//
// Removal of device has been cancelled
//
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDispatchPnp: IRP_MN_CANCEL_REMOVE_DEVICE\n",
SC_DRIVER_NAME)
);
NTStatus = GprCallPcmciaDriver(DeviceObject, Irp);
if (NTStatus == STATUS_SUCCESS) {
NTStatus = IoSetDeviceInterfaceState(
&DeviceExtension->PnPDeviceName,
TRUE
);
SmartcardDebug(
DEBUG_TRACE,
("%s!GprDispatchPnp: Set Pnp Interface state to TRUE, status=%s\n",
SC_DRIVER_NAME,
NTStatus)
);
}
break;
case IRP_MN_REMOVE_DEVICE:
//
// Remove our device
//
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDispatchPnp: IRP_MN_REMOVE_DEVICE\n",
SC_DRIVER_NAME)
);
KeSetEvent(&(smartcardExtension->ReaderExtension->ReaderRemoved), 0, FALSE);
GprStopDevice(DeviceObject);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDispatchPnp: call pcmcia\n",
SC_DRIVER_NAME,
NTStatus)
);
NTStatus = GprCallPcmciaDriver(DeviceObject, Irp);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDispatchPnp: Finish with unload driver\n",
SC_DRIVER_NAME,
NTStatus)
);
GprUnloadDevice(DeviceObject);
deviceRemoved = TRUE;
break;
case IRP_MN_SURPRISE_REMOVAL:
//
// Unexpectedly removed our Reader
//
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDispatchPnp: IRP_MN_SURPRISE_REMOVAL\n",
SC_DRIVER_NAME)
);
if ( DeviceExtension->InterruptObject != NULL ) {
IoDisconnectInterrupt(DeviceExtension->InterruptObject);
DeviceExtension->InterruptObject = NULL;
}
KeSetEvent(&(smartcardExtension->ReaderExtension->ReaderRemoved), 0, FALSE);
NTStatus = GprCallPcmciaDriver(DeviceObject, Irp);
break;
default:
// This might be an Irp that is only useful
// for the underlying bus driver
NTStatus = GprCallPcmciaDriver(DeviceObject, Irp);
irpSkipped = TRUE;
break;
}
if (!irpSkipped) {
Irp->IoStatus.Status = NTStatus;
}
IoCompleteRequest(Irp, IO_NO_INCREMENT);
if (deviceRemoved == FALSE) {
SmartcardReleaseRemoveLockWithTag(smartcardExtension, ' PnP');
}
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDispatchPnp: Exit %x\n",
SC_DRIVER_NAME,
NTStatus)
);
return NTStatus;
}
BOOLEAN GprIsr(
IN PKINTERRUPT pkInterrupt,
IN PVOID pvContext
)
/*++
Routine Description
Interrupt Service routine called when an exchange has been processed by the GPR
--*/
{
PDEVICE_EXTENSION DeviceExtension = NULL;
ASSERT(pvContext != NULL);
DeviceExtension = (PDEVICE_EXTENSION) pvContext;
//
//Request a DPC which will complete the pending User I/O Request
//Packet (aka, IRP), if there is one.
//
KeInsertQueueDpc(
&DeviceExtension->DpcObject,
DeviceExtension,
&DeviceExtension->SmartcardExtension
);
return(TRUE);
}
NTSTATUS GprCleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is called by the I/O system when the calling thread terminates
Arguments:
DeviceObject - Pointer to device object for this miniport
Irp - IRP involved.
Return Value:
STATUS_SUCCESS
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension = &deviceExtension->SmartcardExtension;
NTSTATUS NTStatus = STATUS_SUCCESS;
ASSERT(DeviceObject != NULL);
ASSERT(Irp != NULL);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCleanUp: Enter\n",
SC_DRIVER_NAME)
);
IoAcquireCancelSpinLock(&(Irp->CancelIrql));
if (SmartcardExtension->OsData->NotificationIrp) {
// We need to complete the notification irp
IoSetCancelRoutine(
SmartcardExtension->OsData->NotificationIrp,
NULL
);
GprCancelEventWait(
DeviceObject,
SmartcardExtension->OsData->NotificationIrp
);
} else {
IoReleaseCancelSpinLock( Irp->CancelIrql );
}
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCleanUp: Completing IRP %lx\n",
SC_DRIVER_NAME,
Irp)
);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCleanUp: IoCompleteRequest\n",
SC_DRIVER_NAME)
);
IoCompleteRequest(
Irp,
IO_NO_INCREMENT
);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCleanUp: exit %x\n",
SC_DRIVER_NAME,
NTStatus)
);
return(NTStatus);
}
NTSTATUS GprCancelEventWait(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is called by the I/O system
when the irp should be cancelled
Arguments:
DeviceObject - Pointer to device object for this miniport
Irp - IRP involved.
Return Value:
STATUS_CANCELLED
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension = &deviceExtension->SmartcardExtension;
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCancelEventWait: Enter\n",
SC_DRIVER_NAME)
);
ASSERT(Irp == SmartcardExtension->OsData->NotificationIrp);
SmartcardExtension->OsData->NotificationIrp = NULL;
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_CANCELLED;
IoReleaseCancelSpinLock(
Irp->CancelIrql
);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCancelEventWait: Request completed Irp = %lx\n",
SC_DRIVER_NAME,
Irp)
);
IoCompleteRequest(
Irp,
IO_NO_INCREMENT
);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCancelEventWait: Exit\n",
SC_DRIVER_NAME)
);
return STATUS_CANCELLED;
}
VOID GprCardEventDpc(
PKDPC Dpc,
PDEVICE_OBJECT DeviceObject,
PDEVICE_EXTENSION DeviceExtension,
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description :
DPC routine for interrupts generated by the reader when a card is
inserted/removed. This routine is called only when there is a user
pending request on an insertion/removal IOCTL call. It will check
if the Irp exists and its not being cancelled, and it will then
complete it to signal the user event.
--*/
{
ULONG OldState;
ULONG NewState;
READER_EXTENSION *pReaderExt;
KIRQL irql;
ASSERT (DeviceExtension != NULL);
ASSERT (SmartcardExtension != NULL);
pReaderExt = SmartcardExtension->ReaderExtension;
ASSERT (pReaderExt != NULL);
// Read reader status response from the reader.
GprllReadResp(pReaderExt);
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
ASSERT(pReaderExt->Vo != NULL);
OldState = SmartcardExtension->ReaderCapabilities.CurrentState;
if ((pReaderExt->To==0xA2) && (pReaderExt->Lo==4)) {
//
// The TLV answer indicates the status of the card (inserted/removed)
//
if ( (pReaderExt->Vo[1] & 0x80) == 0x80) {
if (SmartcardExtension->ReaderCapabilities.CurrentState <3) {
NewState = SCARD_SWALLOWED;
} else {
NewState = SmartcardExtension->ReaderCapabilities.CurrentState;
}
} else {
NewState = SCARD_ABSENT;
}
// register this state
SmartcardExtension->ReaderCapabilities.CurrentState = NewState;
} else {
KeSetEvent(&(SmartcardExtension->ReaderExtension->GPRAckEvent),0,FALSE);
}
//
// If the caller was waiting on a IOCTL_SMARTCARD_IS_PRESENT or
// IOCTL_SMARTCARD_IS_ABSENT command, complete the request, but
// check first if its being cancelled!
//
if ( (OldState != SmartcardExtension->ReaderCapabilities.CurrentState)) {
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
GprFinishPendingRequest( DeviceObject, STATUS_SUCCESS );
} else {
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
}
}
VOID GprCardPresenceDpc(
IN PKDPC pDpc,
IN PVOID pvContext,
IN PVOID pArg1,
IN PVOID pArg2
)
/*++
Routine Description:
This is the DPC routine called by polling to detect the card insertion/removal
--*/
{
PDEVICE_EXTENSION pDevExt = NULL;
PSMARTCARD_EXTENSION SmartcardExtension = NULL;
LARGE_INTEGER Timeout;
NTSTATUS status;
UNREFERENCED_PARAMETER (pArg1);
UNREFERENCED_PARAMETER (pArg2);
pDevExt = (PDEVICE_EXTENSION) pvContext;
SmartcardExtension = &(pDevExt->SmartcardExtension);
// SmartcardDebug(DEBUG_DRIVER,("------ CARD PRESENCE DPC -> ENTER\n"));
// ISV
// If wait conditions can be satisfied - get hardware.
// Otherwise - just restart Timer to test it next time...
status = testForIdleAndBlock(SmartcardExtension->ReaderExtension);
if (NT_SUCCESS(status)) {
// Send TLV command, to know card state,
// We don't care about return status, we get the response
// from the Interrupt
// SmartcardDebug(DEBUG_DRIVER,("------ CARD PRESENCE DPC -> GOT ACCESS! status %x\n", status));
AskForCardPresence(SmartcardExtension);
// Release hardware
setIdle(SmartcardExtension->ReaderExtension);
}
if (!KeReadStateEvent(&(SmartcardExtension->ReaderExtension->ReaderRemoved))) {
// Restart the polling timer
Timeout.QuadPart = -(10000 * POLLING_TIME);
KeSetTimer(&(SmartcardExtension->ReaderExtension->CardDetectionTimer),
Timeout,
&SmartcardExtension->ReaderExtension->CardDpcObject
);
}
// SmartcardDebug(DEBUG_DRIVER,("------ CARD PRESENCE DPC -> EXIT\n"));
}
VOID GprUnloadDevice(
PDEVICE_OBJECT DeviceObject
)
/*++
Routine description
close connections to smclib.sys and the pcmcia driver, delete symbolic
link and mark the slot as unused.
Arguments
DeviceObject device to unload
--*/
{
PDEVICE_EXTENSION DeviceExtension;
PAGED_CODE();
ASSERT(DeviceObject != NULL);
if (DeviceObject == NULL) {
return;
}
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprUnloadDevice: Enter \n",
SC_DRIVER_NAME)
);
DeviceExtension = DeviceObject->DeviceExtension;
ASSERT(
DeviceExtension->SmartcardExtension.VendorAttr.UnitNo <
GPR_MAX_DEVICE
);
if (DeviceExtension->PnPDeviceName.Buffer != NULL) {
// disble our device so no one can open it
IoSetDeviceInterfaceState(
&DeviceExtension->PnPDeviceName,
FALSE
);
}
// Mark this slot as available
bDeviceSlot[DeviceExtension->SmartcardExtension.VendorAttr.UnitNo] = FALSE;
// report to the lib that the device will be unloaded
if (DeviceExtension->SmartcardExtension.OsData != NULL) {
// finish pending tracking requests
GprFinishPendingRequest(DeviceObject, STATUS_CANCELLED);
ASSERT(DeviceExtension->SmartcardExtension.OsData->NotificationIrp == NULL);
// Wait until we can safely unload the device
SmartcardReleaseRemoveLockAndWait(&DeviceExtension->SmartcardExtension);
}
if (DeviceExtension->SmartcardExtension.ReaderExtension != NULL) {
// Free under reader stuff
if (!KeReadStateTimer(&(DeviceExtension->SmartcardExtension.ReaderExtension->CardDetectionTimer))) {
// Prevent restarting timer by sync functions
KeCancelTimer(&(DeviceExtension->SmartcardExtension.ReaderExtension->CardDetectionTimer));
}
// Detach from the pcmcia driver
if (DeviceExtension->SmartcardExtension.ReaderExtension->AttachedDeviceObject) {
IoDetachDevice(
DeviceExtension->SmartcardExtension.ReaderExtension->AttachedDeviceObject
);
DeviceExtension->SmartcardExtension.ReaderExtension->AttachedDeviceObject = NULL;
}
// free output buffer
if (DeviceExtension->SmartcardExtension.ReaderExtension->Vo) {
ExFreePool(DeviceExtension->SmartcardExtension.ReaderExtension->Vo);
DeviceExtension->SmartcardExtension.ReaderExtension->Vo = NULL;
}
// free ReaderExtension structure
ExFreePool(DeviceExtension->SmartcardExtension.ReaderExtension);
DeviceExtension->SmartcardExtension.ReaderExtension = NULL;
}
if (DeviceExtension->GprWorkStartup != NULL) {
IoFreeWorkItem(DeviceExtension->GprWorkStartup);
DeviceExtension->GprWorkStartup = NULL;
}
if (DeviceExtension->SmartcardExtension.OsData != NULL) {
SmartcardExit(&DeviceExtension->SmartcardExtension);
}
if (DeviceExtension->PnPDeviceName.Buffer != NULL) {
RtlFreeUnicodeString(&DeviceExtension->PnPDeviceName);
DeviceExtension->PnPDeviceName.Buffer = NULL;
}
// delete the device object
IoDeleteDevice(DeviceObject);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprUnloadDevice: Exit \n",
SC_DRIVER_NAME)
);
return;
}
VOID GprUnloadDriver(
PDRIVER_OBJECT DriverObject
)
/*++
Routine Description :
unloads all devices for a given driver object
Arguments
DriverObject context of driver
--*/
{
PAGED_CODE();
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprUnloadDriver\n",
SC_DRIVER_NAME)
);
}
NTSTATUS GprCreateClose(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description
Create / Close Device function
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
PIO_STACK_LOCATION IrpStack;
LARGE_INTEGER Timeout;
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
IrpStack = IoGetCurrentIrpStackLocation( Irp );
// Initialize
Irp->IoStatus.Information = 0;
// dispatch major function
switch ( IrpStack->MajorFunction ) {
case IRP_MJ_CREATE:
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCreateClose: OPEN DEVICE\n",
SC_DRIVER_NAME)
);
NTStatus = SmartcardAcquireRemoveLockWithTag(SmartcardExtension, 'lCrC');
if (NTStatus != STATUS_SUCCESS) {
NTStatus = STATUS_DEVICE_REMOVED;
} else {
Timeout.QuadPart = 0;
// test if the device has been opened already
NTStatus = KeWaitForSingleObject(
&DeviceExtension->ReaderClosed,
Executive,
KernelMode,
FALSE,
&Timeout
);
if (NTStatus == STATUS_SUCCESS) {
DeviceExtension->OpenFlag = TRUE;
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCreateClose: Set Card Detection timer\n",
SC_DRIVER_NAME)
);
// start the detection timer
Timeout.QuadPart = -(10000 * POLLING_TIME);
KeSetTimer(
&(SmartcardExtension->ReaderExtension->CardDetectionTimer),
Timeout,
&SmartcardExtension->ReaderExtension->CardDpcObject
);
KeClearEvent(&DeviceExtension->ReaderClosed);
} else {
// the device is already in use
NTStatus = STATUS_UNSUCCESSFUL;
// release the lock
//SmartcardReleaseRemoveLock(SmartcardExtension);
SmartcardReleaseRemoveLockWithTag(SmartcardExtension, 'lCrC');
}
}
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCreateClose: OPEN DEVICE EXIT %x\n",
SC_DRIVER_NAME, NTStatus)
);
break;
case IRP_MJ_CLOSE:
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCreateClose: CLOSE DEVICE\n",
SC_DRIVER_NAME)
);
// Cancel the card detection timer
//SmartcardReleaseRemoveLock(SmartcardExtension);
SmartcardReleaseRemoveLockWithTag(SmartcardExtension, 'lCrC');
KeSetEvent(&DeviceExtension->ReaderClosed, 0, FALSE);
if (DeviceExtension->OpenFlag == TRUE) {
if (!KeReadStateTimer(&(DeviceExtension->SmartcardExtension.ReaderExtension->CardDetectionTimer))) {
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCreateClose: Cancel Detection timer\n",
SC_DRIVER_NAME)
);
// Prevent restarting timer by sync functions
KeCancelTimer(&(DeviceExtension->SmartcardExtension.ReaderExtension->CardDetectionTimer));
}
DeviceExtension->OpenFlag = FALSE;
}
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCreateClose: CLOSE DEVICE EXIT %x\n",
SC_DRIVER_NAME, NTStatus)
);
break;
default:
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprCreateClose: Exit %x\n",
SC_DRIVER_NAME,
NTStatus)
);
break;
}
Irp->IoStatus.Status = NTStatus;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return NTStatus;
}
VOID GprWorkStartup(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context
)
/*++
Routine Description:
This function start the GPR after the power completion is completed.
This function runs as a system thread at IRQL == PASSIVE_LEVEL.
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension = &deviceExtension->SmartcardExtension;
LARGE_INTEGER Timeout;
NTSTATUS NTStatus;
USHORT i = 0;
KIRQL irql;
BOOLEAN ContinueLoop = TRUE;
UNREFERENCED_PARAMETER(Context);
SmartcardDebug(DEBUG_DRIVER,("------ WORK STARTUP -> ENTER\n"));
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
// remove this call, use a work thread. Klaus!
//
// Reset the reader
//
waitForIdleAndBlock(SmartcardExtension->ReaderExtension);
while ( ContinueLoop ) {
NTStatus = IfdReset(SmartcardExtension);
i++;
if (NTStatus == STATUS_SUCCESS) {
ContinueLoop = FALSE;
} else if (i >= 3) {
ContinueLoop= FALSE;
} else if ( NTStatus == STATUS_DEVICE_REMOVED) {
ContinueLoop= FALSE;
}
}
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprWorkStartup: IfdReset Status: %x\n",
SC_DRIVER_NAME, NTStatus)
);
if (NTStatus != STATUS_SUCCESS) {
SmartcardLogError(
DeviceObject,
GEMSCR0D_UNABLE_TO_INITIALIZE,
NULL,
0
);
// Advise that reader is ready for working
KeSetEvent(&deviceExtension->ReaderStarted, 0, FALSE);
if (SmartcardExtension->ReaderExtension->RestartCardDetection) {
SmartcardExtension->ReaderExtension->RestartCardDetection = FALSE;
// Restart the card detection timer
Timeout.QuadPart = -(10000 * POLLING_TIME);
KeSetTimer(
&(SmartcardExtension->ReaderExtension->CardDetectionTimer),
Timeout,
&SmartcardExtension->ReaderExtension->CardDpcObject
);
SmartcardDebug(DEBUG_DRIVER,(" CARD DETECTION RESTARTED!\n"));
}
setIdle(SmartcardExtension->ReaderExtension);
SmartcardDebug(DEBUG_DRIVER,("------ WORK STARTUP -> EXIT\n"));
return;
}
// Do appropriate stuff for resume of hibernate mode.
if ( SmartcardExtension->ReaderExtension->NewDevice == FALSE ) {
// Restart the card detection timer
Timeout.QuadPart = -(10000 * POLLING_TIME);
KeSetTimer(
&(SmartcardExtension->ReaderExtension->CardDetectionTimer),
Timeout,
&SmartcardExtension->ReaderExtension->CardDpcObject
);
// 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->CardPresent ||
SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT) {
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprDevicePowerCompletion: GprFinishPendingRequest\n",
SC_DRIVER_NAME)
);
GprFinishPendingRequest(
DeviceObject,
STATUS_SUCCESS
);
} else {
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
}
}
// Device initialization finish,
// NewDevice help to know it we are in hibernation mode or non
SmartcardExtension->ReaderExtension->NewDevice = FALSE;
// Advise that reader is ready for working
KeSetEvent(&deviceExtension->ReaderStarted, 0, FALSE);
if (SmartcardExtension->ReaderExtension->RestartCardDetection) {
SmartcardExtension->ReaderExtension->RestartCardDetection = FALSE;
// Restart the card detection timer
Timeout.QuadPart = -(10000 * POLLING_TIME);
KeSetTimer(
&(SmartcardExtension->ReaderExtension->CardDetectionTimer),
Timeout,
&SmartcardExtension->ReaderExtension->CardDpcObject
);
SmartcardDebug(DEBUG_DRIVER,(" CARD DETECTION RESTARTED!\n"));
}
setIdle(SmartcardExtension->ReaderExtension);
SmartcardDebug(DEBUG_DRIVER,("------ WORK STARTUP -> EXIT\n"));
}
// Functions to synchronize device execution
VOID setBusy(PREADER_EXTENSION Device)
{
KeClearEvent(&Device->IdleState);
SmartcardDebug(DEBUG_DRIVER,(" DEVICE BUSY\n"));
};
VOID setIdle(PREADER_EXTENSION Device)
{
LARGE_INTEGER Timeout;
KeSetEvent(&Device->IdleState,IO_NO_INCREMENT,FALSE);
SmartcardDebug(DEBUG_DRIVER,(" DEVICE IDLE\n"));
};
NTSTATUS waitForIdle(PREADER_EXTENSION Device)
{
NTSTATUS status;
ASSERT(KeGetCurrentIrql()<=DISPATCH_LEVEL);
status = KeWaitForSingleObject(&Device->IdleState, Executive,KernelMode, FALSE, NULL);
if (!NT_SUCCESS(status)) return STATUS_IO_TIMEOUT;
return STATUS_SUCCESS;
};
NTSTATUS waitForIdleAndBlock(PREADER_EXTENSION Device)
{
if (NT_SUCCESS(waitForIdle(Device))) {
setBusy(Device);
return STATUS_SUCCESS;
} else return STATUS_IO_TIMEOUT;
};
NTSTATUS testForIdleAndBlock(PREADER_EXTENSION Device)
{
ASSERT(KeGetCurrentIrql()<=DISPATCH_LEVEL);
if (KeReadStateEvent(&Device->IdleState)) {
setBusy(Device);
return STATUS_SUCCESS;
}
return STATUS_IO_TIMEOUT;
};
//-------------------------------------------------------------
NTSTATUS GprPower (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
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 status code
--*/
{
NTSTATUS status;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PDEVICE_OBJECT AttachedDeviceObject = ATTACHED_DEVICE_OBJECT;
status = STATUS_SUCCESS;
SmartcardDebug(
DEBUG_ERROR,
("%s!GprPower: Enter\n",
SC_DRIVER_NAME)
);
SmartcardDebug(
DEBUG_ERROR,
("%s!GprPower: Irp = %lx\n",
SC_DRIVER_NAME,
Irp)
);
if (irpStack->MinorFunction == IRP_MN_QUERY_POWER)
status = power_HandleQueryPower(DeviceObject,Irp);
else if (irpStack->MinorFunction == IRP_MN_SET_POWER)
status = power_HandleSetPower(DeviceObject,Irp);
else {
SmartcardDebug(
DEBUG_ERROR,
("%s!GprPower: **** Forwarding Power request down...\n",
SC_DRIVER_NAME)
);
// Default device does not do anything.
// So let's just transfer request to low level driver...
PoStartNextPowerIrp(Irp);// must be done while we own the IRP
IoSkipCurrentIrpStackLocation(Irp);
status = PoCallDriver(AttachedDeviceObject, Irp);
}
SmartcardDebug(
DEBUG_DRIVER,
("%s!GprPower: Exit %lx\n",
SC_DRIVER_NAME,
status)
);
return status;
}
// Manages set power requests
NTSTATUS power_HandleSetPower(PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status = STATUS_SUCCESS;
POWER_STATE sysPowerState, desiredDevicePowerState;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
PDEVICE_OBJECT AttachedDeviceObject = ATTACHED_DEVICE_OBJECT;
KIRQL irql;
if (!Irp) return STATUS_INVALID_PARAMETER;
irpStack = IoGetCurrentIrpStackLocation(Irp);
switch (irpStack->Parameters.Power.Type) {
case SystemPowerState:
// Get input system power state
sysPowerState.SystemState = irpStack->Parameters.Power.State.SystemState;
SmartcardDebug(
DEBUG_ERROR,
("%s!power_HandleSetPower: PowerSystem S%d\n",
SC_DRIVER_NAME,
irpStack->Parameters.Power.State.SystemState - 1)
);
// If system is in working state always set our device to D0
// regardless of the wait state or system-to-device state power map
if ( sysPowerState.SystemState == PowerSystemWorking) {
desiredDevicePowerState.DeviceState = PowerDeviceD0;
KeSetEvent(&deviceExtension->ReaderStarted, 0, FALSE);
SmartcardDebug(
DEBUG_ERROR,
("%s!power_HandleSetPower: PowerSystemWorking, Setting device power D0(ON)...\n",
SC_DRIVER_NAME)
);
} else {
//System reduces power, so do specific for device processing...
// if no wait pending and the system's not in working state, just turn off
desiredDevicePowerState.DeviceState = PowerDeviceD3;
SmartcardDebug(DEBUG_ERROR,
("%s!power_HandleSetPower: Going Device Power D3(off)\n",
SC_DRIVER_NAME));
}
// We've determined the desired device state; are we already in this state?
if (smartcardExtension->ReaderExtension->ReaderPowerState != desiredDevicePowerState.DeviceState) {
SmartcardDebug(
DEBUG_ERROR,
("%s!power_HandleSetPower: Requesting to set DevicePower D%d\n",
SC_DRIVER_NAME,
desiredDevicePowerState.DeviceState - 1));
// Callback will release the lock
status = SmartcardAcquireRemoveLockWithTag(smartcardExtension, 'rwoP');
IoMarkIrpPending(Irp);
// No, request that we be put into this state
// by requesting a new Power Irp from the Pnp manager
deviceExtension->PowerIrp = Irp;
status = PoRequestPowerIrp (DeviceObject,
IRP_MN_SET_POWER,
desiredDevicePowerState,
// completion routine will pass the Irp down to the PDO
(PREQUEST_POWER_COMPLETE)onPowerRequestCompletion,
DeviceObject, NULL);
} else { // Yes, just pass it on to PDO (Physical Device Object)
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
status = PoCallDriver(AttachedDeviceObject, Irp);
}
break;
case DevicePowerState:
SmartcardDebug(
DEBUG_ERROR,
("%s!power_HandleSetPower: Setting Device Power D%d\n",
SC_DRIVER_NAME,
irpStack->Parameters.Power.State.DeviceState - 1));
// 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.
// For requests to DeviceState D0 ( fully on ), sets fGoingToD0 flag TRUE
// to flag that we must set a completion routine and update
// deviceExtension->CurrentDevicePowerState there.
// In the case of powering up to fully on, we really want to make sure
// the process is completed before updating our CurrentDevicePowerState,
// so no IO will be attempted or accepted before we're really ready.
if (irpStack->Parameters.Power.State.DeviceState==PowerDeviceD3) {
// save the current card state
KeAcquireSpinLock(&smartcardExtension->OsData->SpinLock,
&irql);
smartcardExtension->ReaderExtension->CardPresent =
smartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT;
if (smartcardExtension->ReaderExtension->CardPresent) {
KeReleaseSpinLock(&smartcardExtension->OsData->SpinLock,
irql);
SmartcardDebug(
DEBUG_DRIVER,
("%s!power_HandleSetPower: Power down card....\n",
SC_DRIVER_NAME));
smartcardExtension->MinorIoControlCode = SCARD_POWER_DOWN;
GprCbReaderPower(smartcardExtension);
} else {
KeReleaseSpinLock(&smartcardExtension->OsData->SpinLock,
irql);
}
if (!KeReadStateTimer(&smartcardExtension->ReaderExtension->CardDetectionTimer)) {
SmartcardDebug(DEBUG_DRIVER,(" STOP CARD DETECTION!\n"));
smartcardExtension->ReaderExtension->RestartCardDetection = TRUE;
// Stop detection for during power events
KeCancelTimer(&smartcardExtension->ReaderExtension->CardDetectionTimer);
}
// If there is a pending card tracking request, setting
// this flag will prevent completion of the request
// when the system will be waked up again.
smartcardExtension->ReaderExtension->PowerRequest = TRUE;
desiredDevicePowerState.DeviceState = PowerDeviceD3;
PoSetPowerState(DeviceObject,DevicePowerState,desiredDevicePowerState);
// save the current power state of the reader
smartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderOff;
// Forward Irp down...
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
} else {
status = SmartcardAcquireRemoveLockWithTag(smartcardExtension, 'rwoP');
SmartcardDebug(DEBUG_ERROR,
("%s!power_HandleSetPower: Going to device power D0...\n",
SC_DRIVER_NAME));
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
onDevicePowerUpComplete,
// Always pass FDO to completion routine as its Context;
// This is because the DriverObject passed by the system to the routine
// is the Physical Device Object ( PDO ) not the Functional Device Object ( FDO )
DeviceObject,
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
}
status = PoCallDriver(AttachedDeviceObject, Irp);
break;
}
return status;
}
// Manages device power up
NTSTATUS onDevicePowerUpComplete(
IN PDEVICE_OBJECT NullDeviceObject,
IN PIRP Irp,
IN PVOID DeviceObject
)
{
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
POWER_STATE desiredDevicePowerState;
SmartcardDebug(DEBUG_DRIVER,
("%s!onDevicePowerUpComplete: Enter Device Power Up...\n",
SC_DRIVER_NAME));
// If the lower driver returned PENDING, mark our stack location as pending also.
if (Irp->PendingReturned) IoMarkIrpPending(Irp);
irpStack = IoGetCurrentIrpStackLocation (Irp);
// We can assert that we're a device powerup-to D0 request,
// because that was the only type of request we set a completion routine
// for in the first place
ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
ASSERT(irpStack->MinorFunction == IRP_MN_SET_POWER);
ASSERT(irpStack->Parameters.Power.Type==DevicePowerState);
ASSERT(irpStack->Parameters.Power.State.DeviceState==PowerDeviceD0);
// We've got power up request, so...
// Report everybody that reader is powered up again!
smartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderWorking;
// GPR400 Check Hardware
if (NT_SUCCESS(IfdCheck(smartcardExtension))) {
// StartGpr in a worker thread.
IoQueueWorkItem(
deviceExtension->GprWorkStartup,
(PIO_WORKITEM_ROUTINE) GprWorkStartup,
DelayedWorkQueue,
NULL);
} else {
SmartcardDebug(
DEBUG_ERROR,
("%s!GprDevicePowerCompletion: Reader is in Bad State\n",
SC_DRIVER_NAME)
);
}
smartcardExtension->ReaderExtension->PowerRequest = FALSE;
// Now that we know we've let the lower drivers do what was needed to power up,
// we can set our device extension flags accordingly
SmartcardReleaseRemoveLockWithTag(smartcardExtension, 'rwoP');
// Report our state to Power manager...
desiredDevicePowerState.DeviceState = PowerDeviceD0;
PoSetPowerState(DeviceObject,DevicePowerState,desiredDevicePowerState);
PoStartNextPowerIrp(Irp);
SmartcardDebug(DEBUG_DRIVER,
("%s!onDevicePowerUpComplete: Exit for the device state D0...\n",
SC_DRIVER_NAME));
return status;
}
// Manages system power transitions
NTSTATUS onPowerRequestCompletion(
IN PDEVICE_OBJECT NullDeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID DeviceObject,
IN PIO_STATUS_BLOCK IoStatus
)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
PDEVICE_OBJECT AttachedDeviceObject = ATTACHED_DEVICE_OBJECT;
PIRP Irp;
SmartcardDebug(DEBUG_DRIVER,
("%s!onPowerRequestCompletion: Enter...\n",
SC_DRIVER_NAME));
// Get the Irp we saved for later processing in BulkUsb_ProcessPowerIrp()
// when we decided to request the Power Irp that this routine
// is the completion routine for.
Irp = deviceExtension->PowerIrp;
// We will return the status set by the PDO for the power request we're completing
status = IoStatus->Status;
smartcardExtension->ReaderExtension->ReaderPowerState = PowerState.DeviceState;
// we must pass down to the next driver in the stack
IoCopyCurrentIrpStackLocationToNext(Irp);
// Calling PoStartNextPowerIrp() indicates that the driver is finished
// with the previous power IRP, if any, and is ready to handle the next power IRP.
// It must be called for every power IRP.Although power IRPs are completed only once,
// typically by the lowest-level driver for a device, PoStartNextPowerIrp must be called
// for every stack location. Drivers must call PoStartNextPowerIrp while the current IRP
// stack location points to the current driver. Therefore, this routine must be called
// before IoCompleteRequest, IoSkipCurrentStackLocation, and PoCallDriver.
PoStartNextPowerIrp(Irp);
// PoCallDriver is used to pass any power IRPs to the PDO instead of IoCallDriver.
// When passing a power IRP down to a lower-level driver, the caller should use
// IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext to copy the IRP to
// the next stack location, then call PoCallDriver. Use IoCopyCurrentIrpStackLocationToNext
// if processing the IRP requires setting a completion routine, or IoSkipCurrentStackLocation
// if no completion routine is needed.
PoCallDriver(AttachedDeviceObject,Irp);
deviceExtension->PowerIrp = NULL;
SmartcardReleaseRemoveLockWithTag(smartcardExtension, 'rwoP');
SmartcardDebug(DEBUG_DRIVER,
("%s!onPowerRequestCompletion: Exit...\n",
SC_DRIVER_NAME));
return status;
}
NTSTATUS power_HandleQueryPower(PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
PDEVICE_OBJECT AttachedDeviceObject = ATTACHED_DEVICE_OBJECT;
NTSTATUS status = STATUS_SUCCESS;
KIRQL irql;
SmartcardDebug(
DEBUG_ERROR,
("%s!power_HandleQueryPower: Enter QueryPower...\n",
SC_DRIVER_NAME));
KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
if (deviceExtension->IoCount != 0)
{ // can't go to sleep mode since the reader is busy.
KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
status = Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
Irp->IoStatus.Information = 0;
PoStartNextPowerIrp(Irp);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
// Block any further ioctls
KeClearEvent(&deviceExtension->ReaderStarted);
SmartcardDebug(DEBUG_DRIVER,
("%s!power_HandleQueryPower: Reader BLOCKED!!!!!!!...\n",
SC_DRIVER_NAME));
Irp->IoStatus.Status = STATUS_SUCCESS;
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
status = PoCallDriver(AttachedDeviceObject, Irp);
return status;
}