windows-nt/Source/XPSP1/NT/drivers/smartcrd/scmstcs/cbhndlr.c
2020-09-26 16:20:57 +08:00

947 lines
22 KiB
C

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) SCM Microsystems, 1998 - 1999
//
// File: cbhndlr.c
//
//--------------------------------------------------------------------------
#if defined( SMCLIB_VXD )
#include "Driver98.h"
#else
#include "DriverNT.h"
#endif
#include "SerialIF.h"
#include "STCCmd.h"
#include "CBHndlr.h"
#include "T0Hndlr.h"
NTSTATUS
CBCardPower(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
CBCardPower:
callback handler for SMCLIB RDF_CARD_POWER
Arguments:
SmartcardExtension context of call
Return Value:
STATUS_SUCCESS
STATUS_NO_MEDIA
STATUS_TIMEOUT
STATUS_BUFFER_TOO_SMALL
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
UCHAR ATRBuffer[ ATR_SIZE ];
ULONG ATRLength;
PREADER_EXTENSION ReaderExtension;
SERIAL_TIMEOUTS Timeouts;
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBCardPower Enter\n" ));
ReaderExtension = SmartcardExtension->ReaderExtension;
// discard old ATR
SmartcardExtension->CardCapabilities.ATR.Length = 0;
SmartcardExtension->CardCapabilities.Protocol.Selected =
SCARD_PROTOCOL_UNDEFINED;
// set standard timeouts for the worker thread
Timeouts.ReadIntervalTimeout = SR_READ_INTERVAL_TIMEOUT;
Timeouts.ReadTotalTimeoutConstant = SR_READ_TOTAL_TIMEOUT_CONSTANT;
Timeouts.ReadTotalTimeoutMultiplier = 0;
Timeouts.WriteTotalTimeoutConstant = SR_WRITE_TOTAL_TIMEOUT_CONSTANT;
Timeouts.WriteTotalTimeoutMultiplier = 0;
NTStatus = IFSerialIoctl(
ReaderExtension,
IOCTL_SERIAL_SET_TIMEOUTS,
&Timeouts,
sizeof(Timeouts),
NULL,
0
);
ASSERT(NTStatus == STATUS_SUCCESS);
// set the ATR timeout in milli sec
ReaderExtension->ReadTimeout = 1500;
switch (SmartcardExtension->MinorIoControlCode)
{
case SCARD_WARM_RESET:
// if the card was not powerd, fall through to cold reset
if( SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_SWALLOWED )
{
// reset the card
ATRLength = ATR_SIZE;
NTStatus = STCReset(
ReaderExtension,
0, // not used: ReaderExtension->Device,
TRUE, // warm reset
ATRBuffer,
&ATRLength
);
break;
}
// warm reset not possible because card was not powerd
case SCARD_COLD_RESET:
// reset the card
ATRLength = ATR_SIZE;
NTStatus = STCReset(
ReaderExtension,
0, // not used: ReaderExtension->Device,
FALSE, // cold reset
ATRBuffer,
&ATRLength
);
break;
case SCARD_POWER_DOWN:
// discard old card status
ATRLength = 0;
STCPowerOff( ReaderExtension );
NTStatus = STATUS_SUCCESS;
CBUpdateCardState( SmartcardExtension, SCARD_PRESENT );
break;
}
// finish the request
if( NTStatus == STATUS_SUCCESS )
{
// update all neccessary data if an ATR was received
if( ATRLength > 2 )
{
// copy ATR to user buffer buffer
if( ATRLength <= SmartcardExtension->IoRequest.ReplyBufferLength )
{
SysCopyMemory(
SmartcardExtension->IoRequest.ReplyBuffer,
ATRBuffer,
ATRLength
);
*SmartcardExtension->IoRequest.Information = ATRLength;
}
else
{
NTStatus = STATUS_BUFFER_TOO_SMALL;
}
// copy ATR to card capability buffer
if( ATRLength <= MAXIMUM_ATR_LENGTH )
{
SysCopyMemory(
SmartcardExtension->CardCapabilities.ATR.Buffer,
ATRBuffer,
ATRLength
);
SmartcardExtension->CardCapabilities.ATR.Length =
(UCHAR)ATRLength;
// let the lib update the card capabilities
NTStatus = SmartcardUpdateCardCapabilities(
SmartcardExtension
);
}
else
{
NTStatus = STATUS_BUFFER_TOO_SMALL;
}
if( NTStatus == STATUS_SUCCESS )
{
ULONG minWaitTime;
// set the stc registers
CBSynchronizeSTC( SmartcardExtension );
// now set the new - card specific - timeouts
if( SmartcardExtension->CardCapabilities.Protocol.Selected ==
SCARD_PROTOCOL_T1 )
{
ReaderExtension->ReadTimeout =
Timeouts.ReadTotalTimeoutConstant =
SmartcardExtension->CardCapabilities.T1.BWT / 1000;
Timeouts.ReadIntervalTimeout =
SmartcardExtension->CardCapabilities.T1.CWT / 1000;
}
else
{
ReaderExtension->ReadTimeout =
Timeouts.ReadIntervalTimeout =
Timeouts.ReadTotalTimeoutConstant =
SmartcardExtension->CardCapabilities.T0.WT / 1000 * 5;
}
minWaitTime = (KeQueryTimeIncrement() / 10000) * 5;
if (Timeouts.ReadTotalTimeoutConstant < minWaitTime) {
Timeouts.ReadTotalTimeoutConstant = minWaitTime;
}
if (Timeouts.ReadIntervalTimeout < minWaitTime) {
Timeouts.ReadIntervalTimeout = minWaitTime;
}
if (ReaderExtension->ReadTimeout < minWaitTime) {
ReaderExtension->ReadTimeout = minWaitTime;
}
// set standard timeouts for the worker thread
Timeouts.ReadTotalTimeoutMultiplier = 0;
NTStatus = IFSerialIoctl(
ReaderExtension,
IOCTL_SERIAL_SET_TIMEOUTS,
&Timeouts,
sizeof(Timeouts),
NULL,
0
);
ASSERT(NTStatus == STATUS_SUCCESS);
}
}
}
SmartcardDebug(
DEBUG_TRACE,
( "SCMSTCS!CBCardPower Exit: %X\n",
NTStatus )
);
return( NTStatus );
}
NTSTATUS
CBSetProtocol(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
CBSetProtocol:
callback handler for SMCLIB RDF_SET_PROTOCOL
Arguments:
SmartcardExtension context of call
Return Value:
STATUS_SUCCESS
STATUS_NO_MEDIA
STATUS_TIMEOUT
STATUS_BUFFER_TOO_SMALL
STATUS_INVALID_DEVICE_STATE
STATUS_INVALID_DEVICE_REQUEST
--*/
{
NTSTATUS NTStatus = STATUS_PENDING;
UCHAR PTSRequest[5], PTSReply[5];
ULONG NewProtocol;
PREADER_EXTENSION ReaderExtension;
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBSetProtocol Enter\n" ));
ReaderExtension = SmartcardExtension->ReaderExtension;
NewProtocol = SmartcardExtension->MinorIoControlCode;
// check if the card is already in specific state
if( ( SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC ) &&
( SmartcardExtension->CardCapabilities.Protocol.Selected & NewProtocol ))
{
NTStatus = STATUS_SUCCESS;
}
// protocol supported?
if( !( SmartcardExtension->CardCapabilities.Protocol.Supported & NewProtocol ) ||
!( SmartcardExtension->ReaderCapabilities.SupportedProtocols & NewProtocol ))
{
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
}
// send PTS
while( NTStatus == STATUS_PENDING )
{
// set initial character of PTS
PTSRequest[0] = 0xFF;
// set the format character
if( NewProtocol & SCARD_PROTOCOL_T1 )
{
PTSRequest[1] = 0x11;
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T1;
}
else
{
PTSRequest[1] = 0x10;
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T0;
}
// PTS1 codes Fl and Dl
PTSRequest[2] =
SmartcardExtension->CardCapabilities.PtsData.Fl << 4 |
SmartcardExtension->CardCapabilities.PtsData.Dl;
// check character
PTSRequest[3] = PTSRequest[0] ^ PTSRequest[1] ^ PTSRequest[2];
// write PTSRequest
NTStatus = STCWriteICC1( ReaderExtension, PTSRequest, 4 );
// get response
if( NTStatus == STATUS_SUCCESS )
{
ULONG BufferLength = sizeof(PTSReply);
NTStatus = STCReadICC1(
ReaderExtension,
PTSReply,
&BufferLength,
4
);
if(( NTStatus == STATUS_SUCCESS ) && !SysCompareMemory( PTSRequest, PTSReply, 4))
{
// set the stc registers
SmartcardExtension->CardCapabilities.Dl =
SmartcardExtension->CardCapabilities.PtsData.Dl;
SmartcardExtension->CardCapabilities.Fl =
SmartcardExtension->CardCapabilities.PtsData.Fl;
CBSynchronizeSTC( SmartcardExtension );
// the card replied correctly to the PTS-request
break;
}
}
//
// The card did either NOT reply or it replied incorrectly
// so try default values
//
SmartcardExtension->CardCapabilities.PtsData.Type = PTS_TYPE_DEFAULT;
SmartcardExtension->MinorIoControlCode = SCARD_COLD_RESET;
NTStatus = CBCardPower( SmartcardExtension );
if( NTStatus == STATUS_SUCCESS )
{
NTStatus = STATUS_PENDING;
}
else
{
NTStatus = STATUS_DEVICE_PROTOCOL_ERROR;
}
}
if( NTStatus == STATUS_TIMEOUT )
{
NTStatus = STATUS_IO_TIMEOUT;
}
if( NTStatus == STATUS_SUCCESS )
{
ULONG minWaitTime;
SERIAL_TIMEOUTS Timeouts;
if( SmartcardExtension->CardCapabilities.Protocol.Selected ==
SCARD_PROTOCOL_T1 )
{
ReaderExtension->ReadTimeout =
Timeouts.ReadTotalTimeoutConstant =
SmartcardExtension->CardCapabilities.T1.BWT / 1000;
Timeouts.ReadIntervalTimeout =
SmartcardExtension->CardCapabilities.T1.CWT / 1000;
}
else
{
ReaderExtension->ReadTimeout =
Timeouts.ReadIntervalTimeout =
Timeouts.ReadTotalTimeoutConstant =
SmartcardExtension->CardCapabilities.T0.WT / 1000 * 5;
}
minWaitTime = (KeQueryTimeIncrement() / 10000) * 5;
if (Timeouts.ReadTotalTimeoutConstant < minWaitTime) {
Timeouts.ReadTotalTimeoutConstant = minWaitTime;
}
if (Timeouts.ReadIntervalTimeout < minWaitTime) {
Timeouts.ReadIntervalTimeout = minWaitTime;
}
if (ReaderExtension->ReadTimeout < minWaitTime) {
ReaderExtension->ReadTimeout = minWaitTime;
}
Timeouts.WriteTotalTimeoutConstant = SR_WRITE_TOTAL_TIMEOUT_CONSTANT;
Timeouts.WriteTotalTimeoutMultiplier = 0;
Timeouts.ReadTotalTimeoutMultiplier = 0;
NTStatus = IFSerialIoctl(
ReaderExtension,
IOCTL_SERIAL_SET_TIMEOUTS,
&Timeouts,
sizeof(Timeouts),
NULL,
0
);
ASSERT(NTStatus == STATUS_SUCCESS);
// indicate that the card is in specific mode
SmartcardExtension->ReaderCapabilities.CurrentState =
SCARD_SPECIFIC;
// return the selected protocol to the caller
*(PULONG) SmartcardExtension->IoRequest.ReplyBuffer =
SmartcardExtension->CardCapabilities.Protocol.Selected;
*SmartcardExtension->IoRequest.Information =
sizeof(SmartcardExtension->CardCapabilities.Protocol.Selected);
}
else
{
SmartcardExtension->CardCapabilities.Protocol.Selected =
SCARD_PROTOCOL_UNDEFINED;
*(PULONG) SmartcardExtension->IoRequest.ReplyBuffer = 0;
*SmartcardExtension->IoRequest.Information = 0;
}
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBSetProtocol: Exit %X\n", NTStatus ));
return( NTStatus );
}
NTSTATUS
CBTransmit(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
CBTransmit:
callback handler for SMCLIB RDF_TRANSMIT
Arguments:
SmartcardExtension context of call
Return Value:
STATUS_SUCCESS
STATUS_NO_MEDIA
STATUS_TIMEOUT
STATUS_INVALID_DEVICE_REQUEST
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBTransmit Enter\n" ));
// dispatch on the selected protocol
switch( SmartcardExtension->CardCapabilities.Protocol.Selected )
{
case SCARD_PROTOCOL_T0:
NTStatus = CBT0Transmit( SmartcardExtension );
break;
case SCARD_PROTOCOL_T1:
NTStatus = CBT1Transmit( SmartcardExtension );
break;
case SCARD_PROTOCOL_RAW:
NTStatus = CBRawTransmit( SmartcardExtension );
break;
default:
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBTransmit Exit: %X\n", NTStatus ));
return( NTStatus );
}
NTSTATUS
CBT0Transmit(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
CBT0Transmit:
finishes the callback RDF_TRANSMIT for the T0 protocol
Arguments:
SmartcardExtension context of call
Return Value:
STATUS_SUCCESS
STATUS_NO_MEDIA
STATUS_TIMEOUT
STATUS_INVALID_DEVICE_REQUEST
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBT0Transmit Enter\n" ));
SmartcardExtension->SmartcardRequest.BufferLength = 0;
SmartcardExtension->SmartcardReply.BufferLength =
SmartcardExtension->SmartcardReply.BufferSize;
// let the lib setup the T=1 APDU & check for errors
NTStatus = SmartcardT0Request( SmartcardExtension );
if( NTStatus == STATUS_SUCCESS )
{
NTStatus = T0_ExchangeData(
SmartcardExtension->ReaderExtension,
SmartcardExtension->SmartcardRequest.Buffer,
SmartcardExtension->SmartcardRequest.BufferLength,
SmartcardExtension->SmartcardReply.Buffer,
&SmartcardExtension->SmartcardReply.BufferLength
);
if( NTStatus == STATUS_SUCCESS )
{
// let the lib evaluate the result & tansfer the data
NTStatus = SmartcardT0Reply( SmartcardExtension );
}
}
SmartcardDebug( DEBUG_TRACE,("SCMSTCS!CBT0Transmit Exit: %X\n", NTStatus ));
return( NTStatus );
}
NTSTATUS
CBT1Transmit(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
CBT1Transmit:
finishes the callback RDF_TRANSMIT for the T1 protocol
Arguments:
SmartcardExtension context of call
Return Value:
STATUS_SUCCESS
STATUS_NO_MEDIA
STATUS_TIMEOUT
STATUS_INVALID_DEVICE_REQUEST
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
ULONG BufferLength,AlreadyRead;
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBT1Transmit Enter\n" ));
//KJ
RtlZeroMemory( SmartcardExtension->SmartcardReply.Buffer,
sizeof(SmartcardExtension->SmartcardReply.Buffer));
// use the lib support to construct the T=1 packets
do {
// no header for the T=1 protocol
SmartcardExtension->SmartcardRequest.BufferLength = 0;
SmartcardExtension->T1.NAD = 0;
// let the lib setup the T=1 APDU & check for errors
NTStatus = SmartcardT1Request( SmartcardExtension );
if( NTStatus == STATUS_SUCCESS )
{
// send command (don't calculate LRC because CRC may be used!)
NTStatus = STCWriteICC1(
SmartcardExtension->ReaderExtension,
SmartcardExtension->SmartcardRequest.Buffer,
SmartcardExtension->SmartcardRequest.BufferLength
);
//
// extend the timeout if a Wtx request was sent by the card. if the
// card responds before the waiting time extension expires, the data are
// buffered in the reader. A delay without polling the reader status
// slows down the performance of the driver, but wtx is an exeption,
// not the rule.
//
if (SmartcardExtension->T1.Wtx)
{
SysDelay(
(( SmartcardExtension->T1.Wtx *
SmartcardExtension->CardCapabilities.T1.BWT + 999L )/
1000L)
);
}
// get response
SmartcardExtension->SmartcardReply.BufferLength = 0;
if( NTStatus == STATUS_SUCCESS )
{
BufferLength = SmartcardExtension->SmartcardReply.BufferSize;
NTStatus = STCReadICC1(
SmartcardExtension->ReaderExtension,
SmartcardExtension->SmartcardReply.Buffer,
&BufferLength,
3
);
// if we have read more then 3 bytes
if(BufferLength > 3)
{
AlreadyRead = BufferLength - 3;
}
else
{
AlreadyRead = 0;
}
if( NTStatus == STATUS_SUCCESS )
{
ULONG Length;
Length = (ULONG)SmartcardExtension->SmartcardReply.Buffer[ LEN_IDX ] + 1;
if( Length + 3 < MIN_BUFFER_SIZE )
{
BufferLength =
SmartcardExtension->SmartcardReply.BufferSize -
Length;
NTStatus = STCReadICC1(
SmartcardExtension->ReaderExtension,
(&SmartcardExtension->SmartcardReply.Buffer[ DATA_IDX ]) + AlreadyRead,
&BufferLength,
Length-AlreadyRead
);
SmartcardExtension->SmartcardReply.BufferLength = Length + 3;
}
else
{
NTStatus = STATUS_BUFFER_TOO_SMALL;
}
}
//
// if STCRead detects an LRC error, ignore it (maybe CRC used). Timeouts will
// be detected by the lib if len=0
//
if(( NTStatus == STATUS_CRC_ERROR ) || ( NTStatus == STATUS_IO_TIMEOUT ))
{
NTStatus = STATUS_SUCCESS;
}
if( NTStatus == STATUS_SUCCESS )
{
// let the lib evaluate the result & setup the next APDU
NTStatus = SmartcardT1Reply( SmartcardExtension );
}
}
}
// continue if the lib wants to send the next packet
} while( NTStatus == STATUS_MORE_PROCESSING_REQUIRED );
if( NTStatus == STATUS_IO_TIMEOUT )
{
NTStatus = STATUS_DEVICE_PROTOCOL_ERROR;
}
SmartcardDebug( DEBUG_TRACE,( "SCMSTCS!CBT1Transmit Exit: %X\n", NTStatus ));
return ( NTStatus );
}
NTSTATUS
CBRawTransmit(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
CBRawTransmit:
finishes the callback RDF_TRANSMIT for the RAW protocol
Arguments:
SmartcardExtension context of call
Return Value:
STATUS_SUCCESS
STATUS_NO_MEDIA
STATUS_TIMEOUT
STATUS_INVALID_DEVICE_REQUEST
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
NTStatus = STATUS_UNSUCCESSFUL;
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBRawTransmit Exit: %X\n", NTStatus ));
return ( NTStatus );
}
NTSTATUS
CBCardTracking(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
CBCardTracking:
callback handler for SMCLIB RDF_CARD_TRACKING. the requested event was
validated by the smclib (i.e. a card removal request will only be passed
if a card is present).
for a win95 build STATUS_PENDING will be returned without any other action.
for NT the cancel routine for the irp will be set to the drivers cancel
routine.
Arguments:
SmartcardExtension context of call
Return Value:
STATUS_PENDING
--*/
{
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBCardTracking Enter\n" ));
#if defined( SMCLIB_VXD )
#else
{
KIRQL CurrentIrql;
// set cancel routine
IoAcquireCancelSpinLock( &CurrentIrql );
IoSetCancelRoutine(
SmartcardExtension->OsData->NotificationIrp,
DrvCancel
);
IoReleaseCancelSpinLock( CurrentIrql );
}
#endif
SmartcardDebug( DEBUG_TRACE, ( "SCMSTCS!CBCardTracking Exit\n" ));
return( STATUS_PENDING );
}
VOID
CBUpdateCardState(
PSMARTCARD_EXTENSION SmartcardExtension,
ULONG RequestedState
)
/*++
CBUpdateCardState:
updates the variable CurrentState in SmartcardExtension
Arguments:
SmartcardExtension context of call
Return Value:
STATUS_SUCCESS
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
UCHAR Status;
KIRQL Irql;
BOOLEAN StateChanged = FALSE;
ULONG NewState = RequestedState;
if (RequestedState == SCARD_UNKNOWN) {
// read card state from reader
NTStatus = STCReadSTCRegister(
SmartcardExtension->ReaderExtension,
ADR_IO_CONFIG,
1,
&Status
);
ASSERT(NTStatus == STATUS_SUCCESS);
if (NTStatus == STATUS_SUCCESS) {
if ((Status & M_SD) == 0) {
NewState = SCARD_ABSENT;
} else {
NewState = SCARD_SWALLOWED;
}
}
}
if (SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_UNKNOWN ||
SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT &&
NewState <= SCARD_ABSENT ||
SmartcardExtension->ReaderCapabilities.CurrentState <= SCARD_ABSENT &&
NewState > SCARD_ABSENT) {
StateChanged = TRUE;
}
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, &Irql);
if(RequestedState != SCARD_UNKNOWN ||
NTStatus == STATUS_SUCCESS && StateChanged)
{
SmartcardExtension->ReaderCapabilities.CurrentState = NewState;
}
#if defined( SMCLIB_VXD )
//
// if a tracking request is pending, finish it (even if an error occured!)
// to prevent a hangup of an application
//
if( SmartcardExtension->OsData->NotificationOverlappedData != NULL )
{
SmartcardCompleteCardTracking( SmartcardExtension );
}
#else
if(StateChanged && SmartcardExtension->OsData->NotificationIrp != NULL)
{
KIRQL CurrentIrql;
IoAcquireCancelSpinLock( &CurrentIrql );
IoSetCancelRoutine( SmartcardExtension->OsData->NotificationIrp, NULL );
IoReleaseCancelSpinLock( CurrentIrql );
SmartcardExtension->OsData->NotificationIrp->IoStatus.Status =
STATUS_SUCCESS;
SmartcardExtension->OsData->NotificationIrp->IoStatus.Information = 0;
IoCompleteRequest(
SmartcardExtension->OsData->NotificationIrp,
IO_NO_INCREMENT
);
SmartcardExtension->OsData->NotificationIrp = NULL;
}
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, Irql);
#endif
}
NTSTATUS
CBSynchronizeSTC(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
CBSynchronizeSTC:
updates the card dependend data of the stc (wait times, ETU...)
Arguments:
SmartcardExtension context of call
Return Value:
STATUS_SUCCESS
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PREADER_EXTENSION ReaderExtension;
ULONG CWT,
BWT,
CGT,
ETU;
UCHAR Dl,
Fl,
N;
PCLOCK_RATE_CONVERSION ClockRateConversion;
PBIT_RATE_ADJUSTMENT BitRateAdjustment;
ReaderExtension = SmartcardExtension->ReaderExtension;
ClockRateConversion = SmartcardExtension->CardCapabilities.ClockRateConversion;
BitRateAdjustment = SmartcardExtension->CardCapabilities.BitRateAdjustment;
// cycle length
Dl = SmartcardExtension->CardCapabilities.Dl;
Fl = SmartcardExtension->CardCapabilities.Fl;
ETU = ClockRateConversion[Fl & 0x0F].F;
ETU /= BitRateAdjustment[ Dl & 0x0F ].DNumerator;
ETU *= BitRateAdjustment[ Dl & 0x0F ].DDivisor;
// ETU += (ETU % 2 == 0) ? 0 : 1;
// a extra guard time of 0xFF means minimum delay in both directions
N = SmartcardExtension->CardCapabilities.N;
if( N == 0xFF )
{
N = 0;
}
// set character waiting & guard time
switch ( SmartcardExtension->CardCapabilities.Protocol.Selected )
{
case SCARD_PROTOCOL_T0:
CWT = 960 * SmartcardExtension->CardCapabilities.T0.WI;
CGT = 14 + N;
break;
case SCARD_PROTOCOL_T1:
CWT = 1000 + ( 0x01 << SmartcardExtension->CardCapabilities.T1.CWI );
BWT = 11 + ( 0x01 << SmartcardExtension->CardCapabilities.T1.BWI ) * 960;
CGT = 15 + N; // 12 + N; sicrypt error
NTStatus = STCSetBWT( ReaderExtension, BWT * ETU );
break;
default:
NTStatus = STATUS_UNSUCCESSFUL;
break;
}
if(( NTStatus == STATUS_SUCCESS ) && ETU )
{
NTStatus = STCSetETU( ReaderExtension, ETU );
if( NTStatus == STATUS_SUCCESS )
{
NTStatus = STCSetCGT( ReaderExtension, CGT );
if( NTStatus == STATUS_SUCCESS )
{
NTStatus = STCSetCWT( ReaderExtension, CWT * ETU );
}
}
}
return( NTStatus );
}