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