📄 pscrnt.c
字号:
ASSERT(deviceExtension->IoCount >= 0);
deviceExtension->IoCount++;
KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
timeout.QuadPart = 0;
status = KeWaitForSingleObject(
&deviceExtension->ReaderRemoved,
Executive,
KernelMode,
FALSE,
&timeout
);
if (status == STATUS_SUCCESS) {
status = STATUS_DEVICE_REMOVED;
} else {
status = SmartcardAcquireRemoveLock(&deviceExtension->SmartcardExtension);
}
if (status != STATUS_SUCCESS) {
// the device has been removed. Fail the call
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_DEVICE_REMOVED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_DEVICE_REMOVED;
}
status = SmartcardDeviceControl(
&(deviceExtension->SmartcardExtension),
Irp
);
SmartcardReleaseRemoveLock(&deviceExtension->SmartcardExtension);
KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
deviceExtension->IoCount--;
ASSERT(deviceExtension->IoCount >= 0);
KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
return status;
}
NTSTATUS
PscrGenericIOCTL(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
PscrGenericIOCTL:
Performs generic callbacks to the reader
Arguments:
SmartcardExtension context of the call
Return Value:
STATUS_SUCCESS
--*/
{
NTSTATUS NTStatus;
PIRP Irp;
PIO_STACK_LOCATION IrpStack;
SmartcardDebug(
DEBUG_TRACE,
( "PSCR!PscrGenericIOCTL: Enter\n" )
);
//
// get pointer to current IRP stack location
//
Irp = SmartcardExtension->OsData->CurrentIrp;
IrpStack = IoGetCurrentIrpStackLocation( Irp );
//
// assume error
//
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
//
// dispatch IOCTL
//
switch( IrpStack->Parameters.DeviceIoControl.IoControlCode )
{
case IOCTL_PSCR_COMMAND:
NTStatus = CmdPscrCommand(
SmartcardExtension->ReaderExtension,
(PUCHAR)Irp->AssociatedIrp.SystemBuffer,
IrpStack->Parameters.DeviceIoControl.InputBufferLength,
(PUCHAR)Irp->AssociatedIrp.SystemBuffer,
IrpStack->Parameters.DeviceIoControl.OutputBufferLength,
(PULONG) &Irp->IoStatus.Information
);
//
// the command could change the active file in the reader file
// system, so make sure that the status file will be selected
// before the next read
//
SmartcardExtension->ReaderExtension->StatusFileSelected = FALSE;
break;
case IOCTL_GET_VERSIONS:
if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
SIZEOF_VERSION_CONTROL )
{
NTStatus = STATUS_BUFFER_TOO_SMALL;
}
else
{
PVERSION_CONTROL VersionControl;
VersionControl = (PVERSION_CONTROL)Irp->AssociatedIrp.SystemBuffer;
VersionControl->SmclibVersion = SmartcardExtension->Version;
VersionControl->DriverMajor = PSCR_MAJOR_VERSION;
VersionControl->DriverMinor = PSCR_MINOR_VERSION;
// update firmware version (changed after update)
CmdGetFirmwareRevision(
SmartcardExtension->ReaderExtension
);
VersionControl->FirmwareMajor =
SmartcardExtension->ReaderExtension->FirmwareMajor;
VersionControl->FirmwareMinor =
SmartcardExtension->ReaderExtension->FirmwareMinor;
VersionControl->UpdateKey =
SmartcardExtension->ReaderExtension->UpdateKey;
Irp->IoStatus.Information = SIZEOF_VERSION_CONTROL;
NTStatus = STATUS_SUCCESS;
}
break;
case IOCTL_SET_TIMEOUT:
{
ULONG NewLimit;
//
// get new timeout limit
//
if ( IrpStack->Parameters.DeviceIoControl.InputBufferLength ==
sizeof( ULONG ))
{
NewLimit = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
}
else
{
NewLimit = 0;
}
//
// report actual timeout limit
//
if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength ==
sizeof( ULONG ))
{
*(PULONG)Irp->AssociatedIrp.SystemBuffer =
SmartcardExtension->ReaderExtension->MaxRetries * DELAY_PSCR_WAIT;
Irp->IoStatus.Information = sizeof( ULONG );
}
//
// set new timeout limit
//
if( NewLimit != 0 )
{
SmartcardExtension->ReaderExtension->MaxRetries =
(NewLimit + DELAY_PSCR_WAIT - 1) / DELAY_PSCR_WAIT;
}
}
NTStatus = STATUS_SUCCESS;
break;
case IOCTL_GET_CONFIGURATION:
//
// return IOBase and IRQ
//
if( IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
SIZEOF_PSCR_CONFIGURATION )
{
NTStatus = STATUS_BUFFER_TOO_SMALL;
}
else
{
PPSCR_CONFIGURATION PSCRConfiguration;
PSCRConfiguration =
(PPSCR_CONFIGURATION)Irp->AssociatedIrp.SystemBuffer;
PSCRConfiguration->IOBase =
SmartcardExtension->ReaderExtension->IOBase;
PSCRConfiguration->IRQ =
SmartcardExtension->ReaderExtension->CurrentIRQ;
Irp->IoStatus.Information = SIZEOF_PSCR_CONFIGURATION;
NTStatus = STATUS_SUCCESS;
}
break;
default:
break;
}
//
// set status of the packet
//
Irp->IoStatus.Status = NTStatus;
SmartcardDebug(
DEBUG_TRACE,
( "PSCR!PscrGenericIOCTL: Exit\n" )
);
return( NTStatus );
}
BOOLEAN
PscrIrqServiceRoutine(
PKINTERRUPT Interrupt,
PDEVICE_EXTENSION DeviceExtension
)
/*++
PscrIrqServiceRoutine:
because the device not supports shared interrupts, the call is passed
to the DPC routine immediately and the IRQ is reported as served
Arguments:
Interrupt interrupt object related to the interrupt
DeviceExtension context of call
Return Value:
STATUS_SUCCESS
--*/
{
SmartcardDebug(
DEBUG_TRACE,
("PSCR!PscrIrqServiceRoutine: Enter\n")
);
//
// When someone yanks out the card the interrupt handler gets called,
// but since there is no card anymore when don't need to schedule a DPC
//
//
// the interrupt is caused by a freeze event. the interface will be
// cleared either by PscrRead() or the DPC routine (depending on
// which is called first)
//
DeviceExtension->SmartcardExtension.ReaderExtension->FreezePending = TRUE;
InterlockedIncrement(&DeviceExtension->PendingInterrupts);
KeInsertQueueDpc(
&DeviceExtension->DpcObject,
DeviceExtension,
&DeviceExtension->SmartcardExtension
);
SmartcardDebug(
DEBUG_TRACE,
( "PSCR!PscrIrqServiceRoutine: Exit\n" )
);
return TRUE;
}
VOID
PscrDpcRoutine(
PKDPC Dpc,
PDEVICE_OBJECT DeviceObject,
PDEVICE_EXTENSION DeviceExtension,
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
PscrDpcRoutine:
finishes interrupt requests. the freeze event data of the reader will be read
& the card state will be updated if data valid
Arguments:
Dpc dpc object related to the call
DeviceObject context of the device
DeviceExtension passed as system argument 1
SmartcardExtension passed as system argument 2
Return Value:
void
--*/
{
NTSTATUS status = STATUS_SUCCESS;
UCHAR Event;
SmartcardDebug(
DEBUG_TRACE,
( "PSCR!PscrInterruptEvent: IoBase %xh\n",
SmartcardExtension->ReaderExtension->IOBase)
);
//
// In case of a card change the reader provides a TLV packet describing
// the event ('freeze event'). If PscrRead was called before the DPC
// routine is called, this event was cleared; in this case the card state
// will be updated by reading the card status file
//
if( DeviceExtension->IoCount > 0 ) {
SmartcardExtension->ReaderExtension->RequestCancelled = TRUE;
}
do {
ASSERT(DeviceExtension->PendingInterrupts < 10);
SmartcardDebug(
DEBUG_TRACE,
( "PSCR!PscrInterruptEvent: PendingInterrupts = %ld\n",
DeviceExtension->PendingInterrupts)
);
PscrFreeze( SmartcardExtension );
} while (InterlockedDecrement(&DeviceExtension->PendingInterrupts) > 0);
}
void
PscrFreeze(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
PscrFreeze:
Read & evaluate freeze data
Arguments:
ReaderExtension context of call
pDevice device which causes the freeze event
Return Value:
STATUS_SUCCESS
STATUS_UNSUCCESSFUL
--*/
{
NTSTATUS NTStatus = STATUS_UNSUCCESSFUL;
PREADER_EXTENSION ReaderExtension;
PPSCR_REGISTERS IOBase;
UCHAR TLVList[9], CardState;
ULONG NBytes;
ULONG Idx, Retries, Status;
UCHAR ReadFreeze[] = { 0x12, 0x00, 0x05, 0x00, 0xB0, 0x00, 0x00, 0x01, 0xA6 };
ReaderExtension = SmartcardExtension->ReaderExtension;
IOBase = ReaderExtension->IOBase;
ReaderExtension->RequestCancelled = FALSE;
for (Retries = 0; Retries < 5; Retries++) {
Status = READ_PORT_UCHAR( &IOBase->CmdStatusReg );
ReaderExtension->InvalidStatus = TRUE;
if(!( Status & PSCR_DATA_AVAIL_BIT ))
{
PscrWriteDirect(
ReaderExtension,
ReadFreeze,
sizeof( ReadFreeze ),
&NBytes
);
SysDelay(15);
}
NTStatus = PscrRead(
ReaderExtension,
(PUCHAR) TLVList,
sizeof( TLVList ),
&NBytes
);
ReaderExtension->InvalidStatus = FALSE;
if( NT_SUCCESS( NTStatus ) && ( NBytes == 9 ))
{
// get result
if( ( TLVList[ PSCR_NAD ] == 0x21 ) &&
( TLVList[ PSCR_INF ] == TAG_FREEZE_EVENTS ))
{
CardState =
(TLVList[PSCR_INF + 2] == DEVICE_ICC1 ? PSCR_ICC_PRESENT : PSCR_ICC_ABSENT);
SmartcardDebug(
DEBUG_TRACE,
( "PSCR!PscrFreeze: CardState = %d\n",
CardState)
);
CBUpdateCardState(SmartcardExtension, CardState, FALSE);
}
}
}
}
NTSTATUS
PscrCancel(
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_TRACE,
("PSCR!PscrCancel: Enter\n")
);
ASSERT(Irp == smartcardExtension->OsData->NotificationIrp);
smartcardExtension->OsData->NotificationIrp = NULL;
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_CANCELLED;
IoReleaseCancelSpinLock(
Irp->CancelIrql
);
SmartcardDebug(
DEBUG_DRIVER,
("PSCR!PscrCancel: Completing wait for Irp = %lx\n",
Irp)
);
IoCompleteRequest(
Irp,
IO_NO_INCREMENT
);
SmartcardDebug(
DEBUG_TRACE,
("PSCR!PscrCancel: Exit\n")
);
return STATUS_CANCELLED;
}
NTSTATUS
PscrCleanup(
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_CANCELLED
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION smartcardExtension = &deviceExtension->SmartcardExtension;
NTSTATUS status = STATUS_SUCCESS;
SmartcardDebug(
DEBUG_TRACE,
("%s!PscrCleanup: Enter\n",
DRIVER_NAME)
);
IoAcquireCancelSpinLock(&(Irp->CancelIrql));
if (smartcardExtension->OsData->NotificationIrp) {
// We need to complete the notification irp
IoSetCancelRoutine(
smartcardExtension->OsData->NotificationIrp,
NULL
);
PscrCancel(
DeviceObject,
smartcardExtension->OsData->NotificationIrp
);
} else {
IoReleaseCancelSpinLock( Irp->CancelIrql );
}
SmartcardDebug(
DEBUG_DRIVER,
("%s!PscrCleanup: Completing IRP %lx\n",
DRIVER_NAME,
Irp)
);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(
Irp,
IO_NO_INCREMENT
);
SmartcardDebug(
DEBUG_TRACE,
("%s!PscrCleanup: Exit\n",
DRIVER_NAME)
);
return STATUS_SUCCESS;
}
void
SysDelay(
ULONG Timeout
)
/*++
SysDelay:
performs a required delay. The usage of KeStallExecutionProcessor is
very nasty, but it happends only if SysDelay is called in the context of
our DPC routine (which is only called if a card change was detected).
For 'normal' IO we have Irql < DISPATCH_LEVEL, so if the reader is polled
while waiting for response we will not block the entire system
Arguments:
Timeout delay in milli seconds
Return Value:
void
--*/
{
LARGE_INTEGER SysTimeout;
if( KeGetCurrentIrql() >= DISPATCH_LEVEL )
{
ULONG Cnt = 20 * Timeout;
while( Cnt-- )
{
// KeStallExecutionProcessor: counted in us
KeStallExecutionProcessor( 50 );
}
}
else
{
SysTimeout.QuadPart = (LONGLONG)-10 * 1000 * Timeout;
// KeDelayExecutionThread: counted in 100 ns
KeDelayExecutionThread( KernelMode, FALSE, &SysTimeout );
}
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -