Windows2003-3790/drivers/smartcrd/stcusb/stccb.c
2020-09-30 16:53:55 +02:00

1309 lines
36 KiB
C

/*++
Copyright (c) 1998 SCM Microsystems, Inc.
Module Name:
StcCb.c
Abstract:
Declaration of callback functions - WDM Version
Revision History:
PP 1.01 01/19/1998
PP 1.00 12/18/1998 Initial Version
--*/
// Include
#include "common.h"
#include "stccmd.h"
#include "stccb.h"
#include "stcusbnt.h"
#include "usbcom.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 Command,
ATRLength;
PREADER_EXTENSION ReaderExtension;
KIRQL irql;
SmartcardDebug( DEBUG_TRACE, ("%s!CBCardPower Enter\n",DRIVER_NAME ));
ReaderExtension = SmartcardExtension->ReaderExtension;
// discard old ATR
SysFillMemory( SmartcardExtension->CardCapabilities.ATR.Buffer, 0x00, 0x40 );
SmartcardExtension->CardCapabilities.ATR.Length = 0;
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
Command = SmartcardExtension->MinorIoControlCode;
switch ( Command )
{
case SCARD_WARM_RESET:
// if the card was not powerd, fall through to cold reset
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
if( SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_SWALLOWED )
{
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
// reset the card
ATRLength = ATR_SIZE;
NTStatus = STCReset(
ReaderExtension,
0, // not used: ReaderExtension->Device,
TRUE, // warm reset
ATRBuffer,
&ATRLength);
break;
} else {
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
}
// 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;
NTStatus = STCPowerOff( ReaderExtension );
if(NTStatus == STATUS_SUCCESS)
{
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_PRESENT;
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
}
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
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 )
{
// set the stc registers
CBSynchronizeSTC( SmartcardExtension );
// set read timeout
if( SmartcardExtension->CardCapabilities.Protocol.Selected == SCARD_PROTOCOL_T1 )
{
ReaderExtension->ReadTimeout =
(ULONG) (SmartcardExtension->CardCapabilities.T1.BWT / 1000);
}
else
{
ReaderExtension->ReadTimeout =
(ULONG) (SmartcardExtension->CardCapabilities.T0.WT / 1000);
if(ReaderExtension->ReadTimeout < 50)
{
ReaderExtension->ReadTimeout = 50; // 50 ms minimum timeout
}
}
}
}
}
SmartcardDebug( DEBUG_TRACE,( "%s!CBCardPower Exit: %X\n", DRIVER_NAME,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;
KIRQL irql;
SmartcardDebug( DEBUG_TRACE, ("%s!CBSetProtocol Enter\n",DRIVER_NAME ));
ReaderExtension = SmartcardExtension->ReaderExtension;
NewProtocol = SmartcardExtension->MinorIoControlCode;
// check if the card is already in specific state
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
if( ( SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC ) &&
( SmartcardExtension->CardCapabilities.Protocol.Selected & NewProtocol ))
{
NTStatus = STATUS_SUCCESS;
}
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
// 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 )&&
(SmartcardExtension->CardCapabilities.Protocol.Supported & 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 = IFWriteSTCData( ReaderExtension, PTSRequest, 4 );
// get response
if( NTStatus == STATUS_SUCCESS )
{
NTStatus = IFReadSTCData( ReaderExtension, PTSReply, 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
//
if( SmartcardExtension->CardCapabilities.PtsData.Type != PTS_TYPE_DEFAULT )
{
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 )
{
// card replied correctly to the PTS request
if( SmartcardExtension->CardCapabilities.Protocol.Selected & SCARD_PROTOCOL_T1 )
{
ReaderExtension->ReadTimeout = SmartcardExtension->CardCapabilities.T1.BWT / 1000;
}
else
{
ULONG ClockRateFactor =
SmartcardExtension->CardCapabilities.ClockRateConversion[SmartcardExtension->CardCapabilities.PtsData.Fl].F;
// check for RFU value, and replace by default value
if( !ClockRateFactor )
ClockRateFactor = 372;
ReaderExtension->ReadTimeout = 960
* SmartcardExtension->CardCapabilities.T0.WI
* ClockRateFactor
/ SmartcardExtension->CardCapabilities.PtsData.CLKFrequency;
// We need to have a minimum timeout anyway
if(ReaderExtension->ReadTimeout <50)
{
ReaderExtension->ReadTimeout =50; // 50 ms minimum timeout
}
}
// indicate that the card is in specific mode
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC;
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
// 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, ("%d!CBSetProtocol: Exit %X\n",DRIVER_NAME, NTStatus ));
return( NTStatus );
}
NTSTATUS
CBGenericIOCTL(
PSMARTCARD_EXTENSION SmartcardExtension)
/*++
Description:
Performs generic callbacks to the reader
Arguments:
SmartcardExtension context of the call
Return Value:
STATUS_SUCCESS
--*/
{
NTSTATUS NTStatus;
SmartcardDebug(
DEBUG_TRACE,
( "%s!CBGenericIOCTL: Enter\n",
DRIVER_NAME));
//
// get pointer to current IRP stack location
//
//
// assume error
//
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
//
// dispatch IOCTL
//
switch( SmartcardExtension->MajorIoControlCode )
{
case IOCTL_WRITE_STC_REGISTER:
NTStatus = IFWriteSTCRegister(
SmartcardExtension->ReaderExtension,
*(SmartcardExtension->IoRequest.RequestBuffer), // Address
(ULONG)(*(SmartcardExtension->IoRequest.RequestBuffer + 1)), // Size
SmartcardExtension->IoRequest.RequestBuffer + 2); // Data
*SmartcardExtension->IoRequest.Information = 1;
if(NTStatus == STATUS_SUCCESS)
{
*(SmartcardExtension->IoRequest.ReplyBuffer) = 0;
}
else
{
*(SmartcardExtension->IoRequest.ReplyBuffer) = 1;
}
break;
case IOCTL_READ_STC_REGISTER:
NTStatus = IFReadSTCRegister(
SmartcardExtension->ReaderExtension,
*(SmartcardExtension->IoRequest.RequestBuffer), // Address
(ULONG)(*(SmartcardExtension->IoRequest.RequestBuffer + 1)), // Size
SmartcardExtension->IoRequest.ReplyBuffer); // Data
if(NTStatus ==STATUS_SUCCESS)
{
*SmartcardExtension->IoRequest.Information =
(ULONG)(*(SmartcardExtension->IoRequest.RequestBuffer + 1));
}
else
{
SmartcardExtension->IoRequest.Information = 0;
}
break;
case IOCTL_WRITE_STC_DATA:
NTStatus = IFWriteSTCData(
SmartcardExtension->ReaderExtension,
SmartcardExtension->IoRequest.RequestBuffer + 1, // Data
(ULONG)(*(SmartcardExtension->IoRequest.RequestBuffer))); // Size
*SmartcardExtension->IoRequest.Information = 1;
if(NTStatus == STATUS_SUCCESS)
{
*(SmartcardExtension->IoRequest.ReplyBuffer) = 0;
}
else
{
*(SmartcardExtension->IoRequest.ReplyBuffer) = 1;
}
break;
case IOCTL_READ_STC_DATA:
NTStatus = IFReadSTCData(
SmartcardExtension->ReaderExtension,
SmartcardExtension->IoRequest.ReplyBuffer, // Data
(ULONG)(*(SmartcardExtension->IoRequest.RequestBuffer))); // Size
if(NTStatus ==STATUS_SUCCESS)
{
*SmartcardExtension->IoRequest.Information =
(ULONG)(*(SmartcardExtension->IoRequest.RequestBuffer));
}
else
{
SmartcardExtension->IoRequest.Information = 0;
}
break;
default:
break;
}
SmartcardDebug(
DEBUG_TRACE,
( "%s!CBGenericIOCTL: Exit\n",
DRIVER_NAME));
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, ("%s!CBTransmit Enter\n",DRIVER_NAME ));
// 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, ("%s!CBTransmit Exit: %X\n",DRIVER_NAME, NTStatus ));
return( NTStatus );
}
NTSTATUS
T0_ExchangeData(
PREADER_EXTENSION ReaderExtension,
PUCHAR pRequest,
ULONG RequestLen,
PUCHAR pReply,
PULONG pReplyLen)
/*++
Routine Description:
T=0 management
Arguments:
ReaderExtension Context of the call
pRequest Request buffer
RequestLen Request buffer length
pReply Reply buffer
pReplyLen Reply buffer length
Return Value:
STATUS_SUCCESS
Status returned by IFReadSTCData or IFWriteSTCData
--*/
{
NTSTATUS NTStatus = STATUS_SUCCESS;
BOOLEAN Direction;
UCHAR Ins,
Pcb = 0;
ULONG Len,
DataIdx;
KPRIORITY PreviousPriority;
BOOLEAN PriorityBoost = FALSE;
if (ReaderExtension->Chosen_Priority > KeQueryPriorityThread(KeGetCurrentThread())) {
SmartcardDebug(
DEBUG_TRACE,
( "%s!T0_ExchangeData: Setting priority: 0x%x\n",
DRIVER_NAME,
ReaderExtension->Chosen_Priority));
PriorityBoost = TRUE;
PreviousPriority = KeSetPriorityThread(KeGetCurrentThread(),
ReaderExtension->Chosen_Priority);
}
// get direction
Ins = pRequest[ INS_IDX ] & 0xFE;
Len = pRequest[ P3_IDX ];
if( RequestLen == 5 )
{
Direction = ISO_OUT;
DataIdx = 0;
// For an ISO OUT command Len=0 means that the host expect an
// 256 byte answer
if( !Len )
{
Len = 0x100;
}
// Add 2 for SW1 SW2
Len+=2;
}
else
{
Direction = ISO_IN;
DataIdx = 5;
}
// send header CLASS,INS,P1,P2,P3
NTStatus = IFWriteSTCData( ReaderExtension, pRequest, 5 );
if( NTStatus == STATUS_SUCCESS )
{
NTStatus = STATUS_MORE_PROCESSING_REQUIRED;
}
while( NTStatus == STATUS_MORE_PROCESSING_REQUIRED )
{
// PCB reading
NTStatus = IFReadSTCData( ReaderExtension, &Pcb, 1 );
if( NTStatus == STATUS_SUCCESS )
{
if( Pcb == 0x60 )
{
// null byte?
NTStatus = STATUS_MORE_PROCESSING_REQUIRED;
continue;
}
else if( ( Pcb & 0xFE ) == Ins )
{
// transfer all
if( Direction == ISO_IN )
{
// write remaining data
NTStatus = IFWriteSTCData( ReaderExtension, pRequest + DataIdx, Len );
if( NTStatus == STATUS_SUCCESS )
{
// if all data successful written the status word is expected
NTStatus = STATUS_MORE_PROCESSING_REQUIRED;
Direction = ISO_OUT;
DataIdx = 0;
Len = 2;
}
}
else
{
// read remaining data
NTStatus = IFReadSTCData( ReaderExtension, pReply + DataIdx, Len );
DataIdx += Len;
}
}
else if( (( Pcb & 0xFE ) ^ Ins ) == 0xFE )
{
// transfer next
if( Direction == ISO_IN )
{
// write next
NTStatus = IFWriteSTCData( ReaderExtension, pRequest + DataIdx, 1 );
if( NTStatus == STATUS_SUCCESS )
{
DataIdx++;
// if all data successful written the status word is expected
if( --Len == 0 )
{
Direction = ISO_OUT;
DataIdx = 0;
Len = 2;
}
NTStatus = STATUS_MORE_PROCESSING_REQUIRED;
}
}
else
{
// read next
NTStatus = IFReadSTCData( ReaderExtension, pReply + DataIdx, 1 );
if( NTStatus == STATUS_SUCCESS )
{
NTStatus = STATUS_MORE_PROCESSING_REQUIRED;
if (Len == 0) {
// we should have be done reading by now.
NTStatus = STATUS_DEVICE_PROTOCOL_ERROR;
break;
}
Len--;
DataIdx++;
}
}
}
else if( (( Pcb & 0x60 ) == 0x60 ) || (( Pcb & 0x90 ) == 0x90 ) )
{
if( Direction == ISO_IN )
{
Direction = ISO_OUT;
DataIdx = 0;
}
// SW1
*pReply = Pcb;
// read SW2 and leave
NTStatus = IFReadSTCData( ReaderExtension, &Pcb, 1 );
*(pReply + 1) = Pcb;
DataIdx += 2;
}
else
{
NTStatus = STATUS_UNSUCCESSFUL;
}
}
}
if(( NTStatus == STATUS_SUCCESS ) && ( pReplyLen != NULL ))
{
*pReplyLen = DataIdx;
}
if (PriorityBoost) {
SmartcardDebug(
DEBUG_TRACE,
( "%s!T0_ExchangeData: Setting priority: 0x%x\n",
DRIVER_NAME,
PreviousPriority));
PreviousPriority = KeSetPriorityThread(KeGetCurrentThread(),
PreviousPriority);
}
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, ("%s!CBT0Transmit Enter\n",DRIVER_NAME ));
SmartcardExtension->SmartcardRequest.BufferLength = 0;
// 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,("%s!CBT0Transmit Exit: %X\n",DRIVER_NAME, 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;
KPRIORITY PreviousPriority;
BOOLEAN PriorityBoost = FALSE;
SmartcardDebug( DEBUG_TRACE, ("%s!CBT1Transmit Enter\n",DRIVER_NAME ));
// smclib workaround
*(PULONG)&SmartcardExtension->IoRequest.ReplyBuffer[0] = 0x02;
*(PULONG)&SmartcardExtension->IoRequest.ReplyBuffer[4] = sizeof( SCARD_IO_REQUEST );
// 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 )
{
if (SmartcardExtension->ReaderExtension->Chosen_Priority > KeQueryPriorityThread(KeGetCurrentThread())) {
SmartcardDebug(
DEBUG_TRACE,
( "%s!CBT1Transmit: Setting priority: 0x%x\n",
DRIVER_NAME,
SmartcardExtension->ReaderExtension->Chosen_Priority));
PriorityBoost = TRUE;
PreviousPriority = KeSetPriorityThread(KeGetCurrentThread(),
SmartcardExtension->ReaderExtension->Chosen_Priority);
}
// send command (don't calculate LRC because CRC may be used!)
NTStatus = IFWriteSTCData(
SmartcardExtension->ReaderExtension,
SmartcardExtension->SmartcardRequest.Buffer,
SmartcardExtension->SmartcardRequest.BufferLength);
if (PriorityBoost) {
SmartcardDebug(
DEBUG_TRACE,
( "%s!CBT1Transmit: Setting priority: 0x%x\n",
DRIVER_NAME,
PreviousPriority));
PriorityBoost = FALSE;
PreviousPriority = KeSetPriorityThread(KeGetCurrentThread(),
PreviousPriority);
}
// extend read timeout if the card issued a WTX request
if (SmartcardExtension->T1.Wtx)
{
SmartcardExtension->ReaderExtension->ReadTimeout =
( SmartcardExtension->T1.Wtx *
SmartcardExtension->CardCapabilities.T1.BWT + 999L )/
1000L;
}
else
{
// restore timeout
SmartcardExtension->ReaderExtension->ReadTimeout =
(ULONG) (SmartcardExtension->CardCapabilities.T1.BWT / 1000);
}
// get response
SmartcardExtension->SmartcardReply.BufferLength = 0;
if( NTStatus == STATUS_SUCCESS )
{
if (SmartcardExtension->ReaderExtension->Chosen_Priority > KeQueryPriorityThread(KeGetCurrentThread())) {
SmartcardDebug(
DEBUG_TRACE,
( "%s!CBT1Transmit: Setting priority: 0x%x\n",
DRIVER_NAME,
SmartcardExtension->ReaderExtension->Chosen_Priority));
PriorityBoost = TRUE;
PreviousPriority = KeSetPriorityThread(KeGetCurrentThread(),
SmartcardExtension->ReaderExtension->Chosen_Priority);
}
NTStatus = IFReadSTCData(
SmartcardExtension->ReaderExtension,
SmartcardExtension->SmartcardReply.Buffer,
3);
if( NTStatus == STATUS_SUCCESS )
{
ULONG Length;
Length = (ULONG)SmartcardExtension->SmartcardReply.Buffer[ LEN_IDX ] + 1;
if( Length + 3 < MIN_BUFFER_SIZE )
{
NTStatus = IFReadSTCData(
SmartcardExtension->ReaderExtension,
&SmartcardExtension->SmartcardReply.Buffer[ DATA_IDX ],
Length);
SmartcardExtension->SmartcardReply.BufferLength = Length + 3;
}
else
{
NTStatus = STATUS_BUFFER_TOO_SMALL;
}
}
if (PriorityBoost) {
SmartcardDebug(
DEBUG_TRACE,
( "%s!CBT1Transmit: Setting priority: 0x%x\n",
DRIVER_NAME,
PreviousPriority));
PriorityBoost = FALSE;
PreviousPriority = KeSetPriorityThread(KeGetCurrentThread(),
PreviousPriority);
}
//
// 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,( "%s!CBT1Transmit Exit: %X\n",DRIVER_NAME, 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_UNSUCCESSFUL
--*/
{
NTSTATUS NTStatus = STATUS_UNSUCCESSFUL;
SmartcardDebug( DEBUG_TRACE, ("%s!CBRawTransmit Exit: %X\n",DRIVER_NAME, 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
--*/
{
KIRQL CurrentIrql;
SmartcardDebug(
DEBUG_TRACE,
("%s!CBCardTracking Enter\n",
DRIVER_NAME));
// set cancel routine
IoAcquireCancelSpinLock( &CurrentIrql );
IoSetCancelRoutine(
SmartcardExtension->OsData->NotificationIrp,
StcUsbCancel);
IoReleaseCancelSpinLock( CurrentIrql );
SmartcardDebug(
DEBUG_TRACE,
("%s!CBCardTracking Exit\n",
DRIVER_NAME));
return( STATUS_PENDING );
}
NTSTATUS
CBUpdateCardState(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
CBUpdateCardState:
updates the variable CurrentState in SmartcardExtension
Arguments:
SmartcardExtension context of call
Return Value:
STATUS_SUCCESS
--*/
{
NTSTATUS status = STATUS_SUCCESS;
UCHAR cardStatus = 0;
KIRQL irql;
BOOLEAN stateChanged = FALSE;
ULONG oldState;
// read card state
status = IFReadSTCRegister(
SmartcardExtension->ReaderExtension,
ADR_IO_CONFIG,
1,
&cardStatus
);
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
oldState = SmartcardExtension->ReaderCapabilities.CurrentState;
switch(status)
{
case STATUS_NO_MEDIA:
SmartcardExtension->ReaderExtension->ErrorCounter = 0;
SmartcardExtension->ReaderCapabilities.CurrentState =
SCARD_ABSENT;
break;
case STATUS_MEDIA_CHANGED:
SmartcardExtension->ReaderExtension->ErrorCounter = 0;
SmartcardExtension->ReaderCapabilities.CurrentState =
SCARD_PRESENT;
break;
case STATUS_SUCCESS:
SmartcardExtension->ReaderExtension->ErrorCounter = 0;
cardStatus &= M_SD;
if( cardStatus == 0 )
{
SmartcardExtension->ReaderCapabilities.CurrentState =
SCARD_ABSENT;
}
else if( SmartcardExtension->ReaderCapabilities.CurrentState <=
SCARD_ABSENT )
{
SmartcardExtension->ReaderCapabilities.CurrentState =
SCARD_PRESENT;
}
break;
default:
if( ++SmartcardExtension->ReaderExtension->ErrorCounter < ERROR_COUNTER_TRESHOLD )
{
// a unknown status was reported from the reader, so use the previous state
SmartcardExtension->ReaderCapabilities.CurrentState = oldState;
}
else
{
SmartcardLogError(
SmartcardExtension->OsData->DeviceObject,
STCUSB_TOO_MANY_ERRORS,
NULL,
0);
// a report of SCARD_UNKNOWN will force the resource manager to
// disconnect the reader
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_UNKNOWN;
}
break;
}
//
// we need to update the card state if there was a card before hibernate
// stand / by or when the current state has changed.
//
if (SmartcardExtension->ReaderExtension->CardPresent ||
oldState <= SCARD_ABSENT &&
SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT ||
oldState > SCARD_ABSENT &&
SmartcardExtension->ReaderCapabilities.CurrentState <= SCARD_ABSENT) {
stateChanged = TRUE;
SmartcardExtension->ReaderExtension->CardPresent = FALSE;
}
if (stateChanged && SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT) {
PoSetSystemState (ES_USER_PRESENT);
}
if(stateChanged && SmartcardExtension->OsData->NotificationIrp != NULL)
{
KIRQL CurrentIrql;
PIRP pIrp;
IoAcquireCancelSpinLock( &CurrentIrql );
IoSetCancelRoutine( SmartcardExtension->OsData->NotificationIrp, NULL );
IoReleaseCancelSpinLock( CurrentIrql );
SmartcardExtension->OsData->NotificationIrp->IoStatus.Status =
STATUS_SUCCESS;
SmartcardExtension->OsData->NotificationIrp->IoStatus.Information = 0;
SmartcardDebug(
DEBUG_DRIVER,
("%s!CBUpdateCardState: Completing notification irp %lx\n",
DRIVER_NAME,
SmartcardExtension->OsData->NotificationIrp));
pIrp = SmartcardExtension->OsData->NotificationIrp;
SmartcardExtension->OsData->NotificationIrp = NULL;
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, irql);
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
} else {
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, irql);
}
return status;
}
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; // 13 + N; cryptoflex error
break;
case SCARD_PROTOCOL_T1:
CWT = 11 + ( 0x01 << SmartcardExtension->CardCapabilities.T1.CWI );
BWT = 11 + ( 0x01 << SmartcardExtension->CardCapabilities.T1.BWI ) * 960;
CGT = 15 + N ;//13 + N; // 12 + N; sicrypt error
NTStatus = STCSetBWT( ReaderExtension, BWT * ETU );
break;
default:
// restore default CGT
CGT=13;
STCSetCGT( ReaderExtension, CGT);
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 );
}