3371 lines
96 KiB
C
3371 lines
96 KiB
C
|
/*++
|
||
|
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
|
||
|
);
|
||
|
|
||
|
// signal that the reader has been started have been put
|
||
|
// in the worker thread.
|
||
|
//KeSetEvent(&DeviceExtension->ReaderStarted, 0, FALSE);
|
||
|
}
|
||
|
__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
|
||
|
{
|
||
|
// Remove before doing the card detection
|
||
|
//NTStatus = SmartcardAcquireRemoveLock(SmartcardExtension);
|
||
|
NTStatus = SmartcardAcquireRemoveLockWithTag(SmartcardExtension, 'tcoI');
|
||
|
|
||
|
// Cancel the card detection timer
|
||
|
if( ! KeReadStateTimer(&(DeviceExtension->SmartcardExtension.ReaderExtension->CardDetectionTimer)))
|
||
|
{
|
||
|
// Prevent restarting timer by sync functions
|
||
|
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);
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
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;
|
||
|
|
||
|
ASSERT (DeviceExtension != NULL);
|
||
|
|
||
|
// SmartcardExtension = &(DeviceExtension->SmartcardExtension);
|
||
|
ASSERT (SmartcardExtension != NULL);
|
||
|
|
||
|
pReaderExt = SmartcardExtension->ReaderExtension;
|
||
|
ASSERT (pReaderExt != NULL);
|
||
|
// Read reader status response from the reader.
|
||
|
GprllReadResp(pReaderExt);
|
||
|
|
||
|
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))
|
||
|
{
|
||
|
GprFinishPendingRequest( DeviceObject, STATUS_SUCCESS );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
This function is called when the underlying stacks
|
||
|
completed the power transition.
|
||
|
|
||
|
--*/
|
||
|
/*VOID GprSystemPowerCompletion(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN UCHAR MinorFunction,
|
||
|
IN POWER_STATE PowerState,
|
||
|
IN PIRP Irp,
|
||
|
IN PIO_STATUS_BLOCK IoStatus
|
||
|
)
|
||
|
{
|
||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
|
PSMARTCARD_EXTENSION SmartcardExtension = &deviceExtension->SmartcardExtension;
|
||
|
PDEVICE_OBJECT AttachedDeviceObject = deviceExtension->SmartcardExtension.ReaderExtension->AttachedDeviceObject;
|
||
|
UNREFERENCED_PARAMETER (MinorFunction);
|
||
|
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
("%s!GprSystemPowerCompletion: Enter\n",
|
||
|
SC_DRIVER_NAME)
|
||
|
);
|
||
|
|
||
|
//Irp->IoStatus.Information = 0;
|
||
|
//Irp->IoStatus.Status = IoStatus->Status;
|
||
|
|
||
|
//SmartcardReleaseRemoveLock(SmartcardExtension);
|
||
|
SmartcardReleaseRemoveLockWithTag(SmartcardExtension, 'rwoP');
|
||
|
|
||
|
|
||
|
if (PowerState.SystemState == PowerSystemWorking)
|
||
|
{
|
||
|
PoSetPowerState (
|
||
|
DeviceObject,
|
||
|
SystemPowerState,
|
||
|
PowerState
|
||
|
);
|
||
|
}
|
||
|
|
||
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
||
|
PoStartNextPowerIrp(Irp);
|
||
|
PoCallDriver(AttachedDeviceObject,Irp);
|
||
|
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
("%s!GprSystemPowerCompletion: Exit\n",
|
||
|
SC_DRIVER_NAME)
|
||
|
);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
This routine is called after the underlying stack powered
|
||
|
UP the serial port, so it can be used again.
|
||
|
|
||
|
--*/
|
||
|
/*NTSTATUS GprDevicePowerCompletion (
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN PIRP Irp,
|
||
|
IN PSMARTCARD_EXTENSION SmartcardExtension
|
||
|
)
|
||
|
{
|
||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
NTSTATUS NTStatus;
|
||
|
LARGE_INTEGER Timeout;
|
||
|
|
||
|
|
||
|
ASSERT(SmartcardExtension != NULL);
|
||
|
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
("%s!GprDevicePowerCompletion: Enter\n",
|
||
|
SC_DRIVER_NAME)
|
||
|
);
|
||
|
|
||
|
// save the current power state of the reader
|
||
|
SmartcardExtension->ReaderExtension->ReaderPowerState =
|
||
|
PowerReaderWorking;
|
||
|
|
||
|
//SmartcardReleaseRemoveLock(SmartcardExtension);
|
||
|
SmartcardReleaseRemoveLockWithTag(SmartcardExtension, 'rwoP');
|
||
|
|
||
|
|
||
|
// inform the power manager of our state.
|
||
|
PoSetPowerState (
|
||
|
DeviceObject,
|
||
|
DevicePowerState,
|
||
|
irpStack->Parameters.Power.State
|
||
|
);
|
||
|
|
||
|
PoStartNextPowerIrp(Irp);
|
||
|
|
||
|
// Inform that Power mode is finish!
|
||
|
SmartcardExtension->ReaderExtension->PowerRequest = FALSE;
|
||
|
|
||
|
//
|
||
|
// GPR400 Check Hardware
|
||
|
//
|
||
|
NTStatus = IfdCheck(SmartcardExtension);
|
||
|
|
||
|
if (NTStatus == STATUS_SUCCESS)
|
||
|
{
|
||
|
// StartGpr in a worker thread.
|
||
|
IoQueueWorkItem(
|
||
|
deviceExtension->GprWorkStartup,
|
||
|
(PIO_WORKITEM_ROUTINE) GprWorkStartup,
|
||
|
DelayedWorkQueue,
|
||
|
NULL
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SmartcardDebug(
|
||
|
DEBUG_ERROR,
|
||
|
("%s!GprDevicePowerCompletion: Reader in Bad State\n",
|
||
|
SC_DRIVER_NAME)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
("%s!GprDevicePowerCompletion: Exit\n",
|
||
|
SC_DRIVER_NAME)
|
||
|
);
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
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;
|
||
|
BOOLEAN ContinueLoop = TRUE;
|
||
|
|
||
|
UNREFERENCED_PARAMETER(Context);
|
||
|
|
||
|
SmartcardDebug(DEBUG_DRIVER,("------ WORK STARTUP -> ENTER\n"));
|
||
|
|
||
|
|
||
|
/* SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
( "%s!GprWorkStartup: Enter\n",
|
||
|
DRIVER_NAME)
|
||
|
);
|
||
|
*/
|
||
|
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)
|
||
|
{
|
||
|
LARGE_INTEGER Timeout;
|
||
|
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.
|
||
|
//
|
||
|
if(SmartcardExtension->ReaderExtension->CardPresent ||
|
||
|
SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT)
|
||
|
{
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
("%s!GprDevicePowerCompletion: GprFinishPendingRequest\n",
|
||
|
SC_DRIVER_NAME)
|
||
|
);
|
||
|
GprFinishPendingRequest(
|
||
|
DeviceObject,
|
||
|
STATUS_SUCCESS
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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)
|
||
|
{
|
||
|
LARGE_INTEGER Timeout;
|
||
|
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"));
|
||
|
|
||
|
/*
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
( "%s!GprWorkStartup: Exit\n",
|
||
|
DRIVER_NAME)
|
||
|
);
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*++
|
||
|
|
||
|
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 GprPower (
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN PIRP Irp
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS status = STATUS_SUCCESS;
|
||
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
||
|
PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
|
||
|
PDEVICE_OBJECT AttachedDeviceObject;
|
||
|
POWER_STATE powerState;
|
||
|
ACTION action;
|
||
|
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
("%s!GprPower: Enter\n",
|
||
|
SC_DRIVER_NAME)
|
||
|
);
|
||
|
|
||
|
//status = SmartcardAcquireRemoveLock(smartcardExtension);
|
||
|
status = SmartcardAcquireRemoveLockWithTag(smartcardExtension, 'rwoP');
|
||
|
|
||
|
|
||
|
ASSERT(status == STATUS_SUCCESS);
|
||
|
|
||
|
if (!NT_SUCCESS(status))
|
||
|
{
|
||
|
PoStartNextPowerIrp(Irp);
|
||
|
Irp->IoStatus.Status = status;
|
||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
AttachedDeviceObject =
|
||
|
deviceExtension->SmartcardExtension.ReaderExtension->AttachedDeviceObject;
|
||
|
|
||
|
|
||
|
if (irpStack->Parameters.Power.Type == DevicePowerState &&
|
||
|
irpStack->MinorFunction == IRP_MN_SET_POWER)
|
||
|
{
|
||
|
switch (irpStack->Parameters.Power.State.DeviceState)
|
||
|
{
|
||
|
case PowerDeviceD0:
|
||
|
// Turn on the reader
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
("%s!GprPower: PowerDevice D0\n",
|
||
|
SC_DRIVER_NAME)
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// 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,
|
||
|
GprDevicePowerCompletion,
|
||
|
smartcardExtension,
|
||
|
TRUE,
|
||
|
TRUE,
|
||
|
TRUE
|
||
|
);
|
||
|
|
||
|
action = WaitForCompletion;
|
||
|
break;
|
||
|
|
||
|
case PowerDeviceD3:
|
||
|
// Turn off the reader
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
("%s!GprPower: PowerDevice D3\n",
|
||
|
SC_DRIVER_NAME)
|
||
|
);
|
||
|
|
||
|
PoSetPowerState (
|
||
|
DeviceObject,
|
||
|
DevicePowerState,
|
||
|
irpStack->Parameters.Power.State
|
||
|
);
|
||
|
|
||
|
// save the current card state
|
||
|
smartcardExtension->ReaderExtension->CardPresent =
|
||
|
smartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT;
|
||
|
|
||
|
if (smartcardExtension->ReaderExtension->CardPresent)
|
||
|
{
|
||
|
smartcardExtension->MinorIoControlCode = SCARD_POWER_DOWN;
|
||
|
GprCbReaderPower(smartcardExtension);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 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;
|
||
|
|
||
|
// save the current power state of the reader
|
||
|
smartcardExtension->ReaderExtension->ReaderPowerState =
|
||
|
PowerReaderOff;
|
||
|
|
||
|
// cancel the card detection timer
|
||
|
if(!KeReadStateTimer(&(deviceExtension->SmartcardExtension.ReaderExtension->CardDetectionTimer)))
|
||
|
{
|
||
|
// Prevent restarting timer by sync functions
|
||
|
KeCancelTimer(&(deviceExtension->SmartcardExtension.ReaderExtension->CardDetectionTimer));
|
||
|
}
|
||
|
|
||
|
// power down the reader
|
||
|
// We don't care about return status of this function
|
||
|
IfdPowerDown(smartcardExtension);
|
||
|
|
||
|
action = SkipRequest;
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ASSERT(FALSE);
|
||
|
action = SkipRequest;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (irpStack->Parameters.Power.Type == SystemPowerState)
|
||
|
{
|
||
|
//
|
||
|
// The system wants to change the power state.
|
||
|
// We need to translate the system power state to
|
||
|
// a corresponding device power state.
|
||
|
//
|
||
|
|
||
|
POWER_STATE_TYPE powerType = DevicePowerState;
|
||
|
|
||
|
ASSERT(smartcardExtension->ReaderExtension->ReaderPowerState !=
|
||
|
PowerReaderUnspecified);
|
||
|
|
||
|
switch(irpStack->MinorFunction)
|
||
|
{
|
||
|
KIRQL irql;
|
||
|
|
||
|
case IRP_MN_QUERY_POWER:
|
||
|
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
("%s!GprPower: Query Power\n",
|
||
|
SC_DRIVER_NAME)
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// By default we succeed and pass down
|
||
|
//
|
||
|
|
||
|
action = SkipRequest;
|
||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
|
||
|
switch (irpStack->Parameters.Power.State.SystemState)
|
||
|
{
|
||
|
case PowerSystemMaximum:
|
||
|
case PowerSystemWorking:
|
||
|
case PowerSystemSleeping1:
|
||
|
case PowerSystemSleeping2:
|
||
|
break;
|
||
|
|
||
|
case PowerSystemSleeping3:
|
||
|
case PowerSystemHibernate:
|
||
|
case PowerSystemShutdown:
|
||
|
|
||
|
KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
|
||
|
if (deviceExtension->IoCount == 0)
|
||
|
{
|
||
|
// Block any further ioctls
|
||
|
KeClearEvent(&deviceExtension->ReaderStarted);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// can't go to sleep mode since the reader is busy.
|
||
|
status = STATUS_DEVICE_BUSY;
|
||
|
action = CompleteRequest;
|
||
|
}
|
||
|
KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
|
||
|
case IRP_MN_SET_POWER:
|
||
|
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
("%s!GprPower: PowerSystem S%d\n",
|
||
|
SC_DRIVER_NAME,
|
||
|
irpStack->Parameters.Power.State.SystemState - 1)
|
||
|
);
|
||
|
|
||
|
switch (irpStack->Parameters.Power.State.SystemState)
|
||
|
{
|
||
|
case PowerSystemMaximum:
|
||
|
case PowerSystemWorking:
|
||
|
case PowerSystemSleeping1:
|
||
|
case PowerSystemSleeping2:
|
||
|
|
||
|
if (smartcardExtension->ReaderExtension->ReaderPowerState ==
|
||
|
PowerReaderWorking)
|
||
|
{
|
||
|
// We're already in the right state
|
||
|
KeSetEvent(&deviceExtension->ReaderStarted,0,FALSE);
|
||
|
action = CompleteRequest;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
powerState.DeviceState = PowerDeviceD0;
|
||
|
|
||
|
// wake up the underlying stack...
|
||
|
action = MarkPending;
|
||
|
break;
|
||
|
|
||
|
case PowerSystemSleeping3:
|
||
|
case PowerSystemHibernate:
|
||
|
case PowerSystemShutdown:
|
||
|
|
||
|
if (smartcardExtension->ReaderExtension->ReaderPowerState ==
|
||
|
PowerReaderOff)
|
||
|
{
|
||
|
// We're already in the right state
|
||
|
action = CompleteRequest;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
powerState.DeviceState = PowerDeviceD3;
|
||
|
|
||
|
// first, inform the power manager of our new state.
|
||
|
PoSetPowerState (
|
||
|
DeviceObject,
|
||
|
SystemPowerState,
|
||
|
powerState
|
||
|
);
|
||
|
action = MarkPending;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ASSERT(FALSE);
|
||
|
action = CompleteRequest;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch (action)
|
||
|
{
|
||
|
case CompleteRequest:
|
||
|
Irp->IoStatus.Status = status;
|
||
|
Irp->IoStatus.Information = 0;
|
||
|
|
||
|
//SmartcardReleaseRemoveLock(smartcardExtension);
|
||
|
SmartcardReleaseRemoveLockWithTag(smartcardExtension, 'rwoP');
|
||
|
|
||
|
PoStartNextPowerIrp(Irp);
|
||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
break;
|
||
|
|
||
|
case MarkPending:
|
||
|
Irp->IoStatus.Status = STATUS_PENDING;
|
||
|
IoMarkIrpPending(Irp);
|
||
|
status = PoRequestPowerIrp (
|
||
|
DeviceObject,
|
||
|
IRP_MN_SET_POWER,
|
||
|
powerState,
|
||
|
GprSystemPowerCompletion,
|
||
|
Irp,
|
||
|
NULL
|
||
|
);
|
||
|
ASSERT(status == STATUS_PENDING);
|
||
|
break;
|
||
|
|
||
|
case SkipRequest:
|
||
|
//SmartcardReleaseRemoveLock(smartcardExtension);
|
||
|
SmartcardReleaseRemoveLockWithTag(smartcardExtension, 'rwoP');
|
||
|
|
||
|
PoStartNextPowerIrp(Irp);
|
||
|
IoSkipCurrentIrpStackLocation(Irp);
|
||
|
status = PoCallDriver(AttachedDeviceObject, Irp);
|
||
|
break;
|
||
|
|
||
|
case WaitForCompletion:
|
||
|
status = PoCallDriver(AttachedDeviceObject, Irp);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ASSERT(FALSE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
("%s!GprPower: Exit %lx\n",
|
||
|
SC_DRIVER_NAME,
|
||
|
status)
|
||
|
);
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
// 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;
|
||
|
|
||
|
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
|
||
|
smartcardExtension->ReaderExtension->CardPresent =
|
||
|
smartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT;
|
||
|
if (smartcardExtension->ReaderExtension->CardPresent)
|
||
|
{
|
||
|
SmartcardDebug(
|
||
|
DEBUG_DRIVER,
|
||
|
("%s!power_HandleSetPower: Power down card....\n",
|
||
|
SC_DRIVER_NAME));
|
||
|
|
||
|
smartcardExtension->MinorIoControlCode = SCARD_POWER_DOWN;
|
||
|
GprCbReaderPower(smartcardExtension);
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|