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.
3097 lines
107 KiB
3097 lines
107 KiB
/*****************************************************************************
|
|
@doc INT EXT
|
|
******************************************************************************
|
|
* $ProjectName: $
|
|
* $ProjectRevision: $
|
|
*-----------------------------------------------------------------------------
|
|
* $Source: z:/pr/cmbp0/sw/cmbp0.ms/rcs/cmbp0scr.c $
|
|
* $Revision: 1.7 $
|
|
*-----------------------------------------------------------------------------
|
|
* $Author: WFrischauf $
|
|
*-----------------------------------------------------------------------------
|
|
* History: see EOF
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Copyright © 2000 OMNIKEY AG
|
|
******************************************************************************/
|
|
|
|
#include <cmbp0wdm.h>
|
|
#include <cmbp0scr.h>
|
|
#include <cmbp0log.h>
|
|
|
|
|
|
// this is a FI / Fi assignment
|
|
const ULONG Fi[] = { 372, 372, 588, 744, 1116, 1488, 1860, 372,
|
|
372, 512, 768, 1024, 1536, 2048, 372, 372};
|
|
|
|
// this is a DI / Di assignment
|
|
const ULONG Di[] = { 1, 1, 2, 4, 8, 16, 32, 1,
|
|
12, 20, 1, 1, 1, 1, 1, 1};
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_CorrectAtr
|
|
|
|
Routine Description:
|
|
This function checks if the received ATR is valid.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
*****************************************************************************/
|
|
VOID CMMOB_CorrectAtr(
|
|
PUCHAR pbBuffer,
|
|
ULONG ulBufferSize
|
|
)
|
|
{
|
|
UCHAR bNumberHistoricalBytes;
|
|
UCHAR bXorChecksum;
|
|
ULONG i;
|
|
|
|
if (ulBufferSize < 0x09) // mininmum length of a modified ATR
|
|
return ; // ATR is ok
|
|
|
|
// variant 1
|
|
if (pbBuffer[0] == 0x3b &&
|
|
pbBuffer[1] == 0xb4 &&
|
|
pbBuffer[2] == 0x11 &&
|
|
pbBuffer[3] == 0x00 &&
|
|
pbBuffer[4] == 0x81 &&
|
|
pbBuffer[5] == 0x31 &&
|
|
pbBuffer[6] == 0x90 &&
|
|
pbBuffer[7] == 0x73 &&
|
|
ulBufferSize == 13 ) {
|
|
// correct checksum byte
|
|
bXorChecksum = pbBuffer[1];
|
|
for (i=2;i<ulBufferSize-1;i++)
|
|
bXorChecksum ^= pbBuffer[i];
|
|
|
|
if (pbBuffer[ulBufferSize -1 ] != bXorChecksum ) {
|
|
pbBuffer[ulBufferSize -1 ] = bXorChecksum;
|
|
SmartcardDebug(DEBUG_ATR,
|
|
("%s!CorrectAtr: Correcting SAMOS ATR (variant 1)\n", DRIVER_NAME));
|
|
}
|
|
}
|
|
|
|
// variant 2
|
|
if (pbBuffer[0] == 0x3b &&
|
|
pbBuffer[1] == 0xbf &&
|
|
pbBuffer[2] == 0x11 &&
|
|
pbBuffer[3] == 0x00 &&
|
|
pbBuffer[4] == 0x81 &&
|
|
pbBuffer[5] == 0x31 &&
|
|
pbBuffer[6] == 0x90 &&
|
|
pbBuffer[7] == 0x73 &&
|
|
ulBufferSize == 13 ) {
|
|
// correct number of historical bytes
|
|
bNumberHistoricalBytes = 4;
|
|
|
|
pbBuffer[1] &= 0xf0;
|
|
pbBuffer[1] |= bNumberHistoricalBytes;
|
|
|
|
// correct checksum byte
|
|
bXorChecksum = pbBuffer[1];
|
|
for (i=2;i<ulBufferSize-1;i++)
|
|
bXorChecksum ^= pbBuffer[i];
|
|
|
|
pbBuffer[ulBufferSize -1 ] = bXorChecksum;
|
|
SmartcardDebug(DEBUG_ATR,
|
|
("%s!CorrectAtr: Correcting SAMOS ATR (variant 2)\n", DRIVER_NAME));
|
|
}
|
|
|
|
// variant 3
|
|
if (pbBuffer[0] == 0x3b &&
|
|
pbBuffer[1] == 0xbf &&
|
|
pbBuffer[2] == 0x11 &&
|
|
pbBuffer[3] == 0x00 &&
|
|
pbBuffer[4] == 0x81 &&
|
|
pbBuffer[5] == 0x31 &&
|
|
pbBuffer[6] == 0x90 &&
|
|
pbBuffer[7] == 0x73 &&
|
|
ulBufferSize == 9 ) {
|
|
// correct number of historical bytes
|
|
bNumberHistoricalBytes = 0;
|
|
|
|
pbBuffer[1] &= 0xf0;
|
|
pbBuffer[1] |= bNumberHistoricalBytes;
|
|
|
|
// correct checksum byte
|
|
bXorChecksum = pbBuffer[1];
|
|
for (i=2;i<ulBufferSize-1;i++)
|
|
bXorChecksum ^= pbBuffer[i];
|
|
|
|
pbBuffer[ulBufferSize -1 ] = bXorChecksum;
|
|
SmartcardDebug(DEBUG_ATR,
|
|
("%s!CorrectAtr: Correcting SAMOS ATR (variant 3)\n",DRIVER_NAME));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_CardPower:
|
|
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 CMMOB_CardPower (
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
PREADER_EXTENSION ReaderExtension;
|
|
UCHAR pbAtrBuffer[MAXIMUM_ATR_LENGTH];
|
|
ULONG ulAtrLength;
|
|
BOOLEAN fMaxWaitTime=FALSE;
|
|
KIRQL irql;
|
|
|
|
#if DBG || DEBUG
|
|
static PCHAR request[] = { "PowerDown", "ColdReset", "WarmReset"};
|
|
#endif
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!CardPower: Enter, Request = %s\n",
|
|
DRIVER_NAME,request[SmartcardExtension->MinorIoControlCode]));
|
|
|
|
ReaderExtension = SmartcardExtension->ReaderExtension;
|
|
|
|
ReaderExtension->fTActive=TRUE;
|
|
NTStatus = CMMOB_SetFlags1(ReaderExtension);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
goto ExitCardPower;
|
|
}
|
|
|
|
|
|
switch (SmartcardExtension->MinorIoControlCode) {
|
|
case SCARD_WARM_RESET:
|
|
case SCARD_COLD_RESET:
|
|
// try asynchronous cards first
|
|
// because some asynchronous cards
|
|
// do not return 0xFF in the first byte
|
|
NTStatus = CMMOB_PowerOnCard(SmartcardExtension,
|
|
pbAtrBuffer,
|
|
fMaxWaitTime,
|
|
&ulAtrLength);
|
|
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
// try a second time, with maximum waiting time
|
|
fMaxWaitTime=TRUE;
|
|
NTStatus = CMMOB_PowerOnCard(SmartcardExtension,
|
|
pbAtrBuffer,
|
|
fMaxWaitTime,
|
|
&ulAtrLength);
|
|
}
|
|
|
|
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
goto ExitCardPower;
|
|
}
|
|
|
|
// correct ATR in case of old Samos cards, with wrong number of historical bytes / checksum
|
|
CMMOB_CorrectAtr(pbAtrBuffer, ulAtrLength);
|
|
|
|
if (ReaderExtension->CardParameters.fSynchronousCard == FALSE) {
|
|
// copy ATR to smart card structure
|
|
// the lib needs the ATR for evaluation of the card parameters
|
|
|
|
RtlCopyBytes((PVOID)SmartcardExtension->CardCapabilities.ATR.Buffer,
|
|
(PVOID)pbAtrBuffer,
|
|
ulAtrLength);
|
|
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
SmartcardExtension->CardCapabilities.ATR.Length = (UCHAR)ulAtrLength;
|
|
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_NEGOTIABLE;
|
|
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
|
|
NTStatus = SmartcardUpdateCardCapabilities(SmartcardExtension);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
if (!fMaxWaitTime) {
|
|
// try a second time, with maximum waiting time
|
|
fMaxWaitTime=TRUE;
|
|
NTStatus = CMMOB_PowerOnCard(SmartcardExtension,
|
|
pbAtrBuffer,
|
|
fMaxWaitTime,
|
|
&ulAtrLength);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
goto ExitCardPower;
|
|
}
|
|
RtlCopyBytes((PVOID)SmartcardExtension->CardCapabilities.ATR.Buffer,
|
|
(PVOID)pbAtrBuffer,
|
|
ulAtrLength);
|
|
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
SmartcardExtension->CardCapabilities.ATR.Length = (UCHAR)ulAtrLength;
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_NEGOTIABLE;
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
|
|
NTStatus = SmartcardUpdateCardCapabilities(SmartcardExtension);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
goto ExitCardPower;
|
|
}
|
|
} else
|
|
goto ExitCardPower;
|
|
}
|
|
|
|
// -----------------------
|
|
// set parameters
|
|
// -----------------------
|
|
if (SmartcardExtension->CardCapabilities.N != 0xff) {
|
|
// 0 <= N <= 254
|
|
ReaderExtension->CardParameters.bStopBits = 2 + SmartcardExtension->CardCapabilities.N;
|
|
} else {
|
|
// N = 255
|
|
if (SmartcardExtension->CardCapabilities.Protocol.Selected & SCARD_PROTOCOL_T0) {
|
|
// 12 etu for T=0;
|
|
ReaderExtension->CardParameters.bStopBits = 2;
|
|
} else {
|
|
// 11 etu for T=1
|
|
ReaderExtension->CardParameters.bStopBits = 1;
|
|
}
|
|
}
|
|
|
|
if (SmartcardExtension->CardCapabilities.InversConvention) {
|
|
ReaderExtension->CardParameters.fInversRevers = TRUE;
|
|
SmartcardDebug(DEBUG_ATR,
|
|
("%s!Card with invers convention !\n",DRIVER_NAME ));
|
|
}
|
|
|
|
CMMOB_SetCardParameters (ReaderExtension);
|
|
|
|
#if DBG
|
|
{
|
|
ULONG i;
|
|
SmartcardDebug(DEBUG_ATR,("%s!ATR : ",DRIVER_NAME));
|
|
for (i = 0;i < ulAtrLength;i++)
|
|
SmartcardDebug(DEBUG_ATR,("%2.2x ",SmartcardExtension->CardCapabilities.ATR.Buffer[i]));
|
|
SmartcardDebug(DEBUG_ATR,("\n"));
|
|
}
|
|
#endif
|
|
|
|
} else {
|
|
SmartcardExtension->CardCapabilities.ATR.Buffer[0] = 0x3B;
|
|
SmartcardExtension->CardCapabilities.ATR.Buffer[1] = 0x04;
|
|
|
|
RtlCopyBytes((PVOID)&SmartcardExtension->CardCapabilities.ATR.Buffer[2],
|
|
(PVOID)pbAtrBuffer,
|
|
ulAtrLength);
|
|
|
|
ulAtrLength += 2;
|
|
SmartcardExtension->CardCapabilities.ATR.Length = (UCHAR)ulAtrLength;
|
|
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC;
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T0;
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
|
|
NTStatus = SmartcardUpdateCardCapabilities(SmartcardExtension);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
goto ExitCardPower;
|
|
}
|
|
|
|
SmartcardDebug(DEBUG_ATR,("ATR of synchronous smart card : %2.2x %2.2x %2.2x %2.2x\n",
|
|
pbAtrBuffer[0],pbAtrBuffer[1],pbAtrBuffer[2],pbAtrBuffer[3]));
|
|
|
|
}
|
|
|
|
// copy ATR to user space
|
|
if (SmartcardExtension->IoRequest.ReplyBufferLength >=
|
|
SmartcardExtension->CardCapabilities.ATR.Length) {
|
|
RtlCopyBytes((PVOID)SmartcardExtension->IoRequest.ReplyBuffer,
|
|
(PVOID)SmartcardExtension->CardCapabilities.ATR.Buffer,
|
|
SmartcardExtension->CardCapabilities.ATR.Length);
|
|
|
|
*SmartcardExtension->IoRequest.Information = SmartcardExtension->CardCapabilities.ATR.Length;
|
|
} else {
|
|
NTStatus = STATUS_BUFFER_TOO_SMALL;
|
|
*SmartcardExtension->IoRequest.Information = 0;
|
|
}
|
|
|
|
break;
|
|
|
|
case SCARD_POWER_DOWN:
|
|
NTStatus = CMMOB_PowerOffCard(SmartcardExtension);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
goto ExitCardPower;
|
|
}
|
|
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SWALLOWED;
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
|
|
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
ExitCardPower:
|
|
|
|
ReaderExtension->fTActive=FALSE;
|
|
CMMOB_SetFlags1(ReaderExtension);
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!CardPower: Exit %X\n",DRIVER_NAME,NTStatus ));
|
|
|
|
return( NTStatus );
|
|
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Routine Description:
|
|
CMMOB_PowerOnCard
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
*****************************************************************************/
|
|
NTSTATUS CMMOB_PowerOnCard (
|
|
IN PSMARTCARD_EXTENSION SmartcardExtension,
|
|
IN PUCHAR pbATR,
|
|
IN BOOLEAN fMaxWaitTime,
|
|
OUT PULONG pulATRLength
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
KTIMER TimerWait;
|
|
UCHAR bPowerCmd;
|
|
ULONG ulCardType;
|
|
ULONG ulBytesReceived;
|
|
UCHAR bFirstByte;
|
|
LONG lWaitTime;
|
|
LARGE_INTEGER liWaitTime;
|
|
BOOLEAN fTimeExpired;
|
|
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!PowerOnCard: Enter\n",DRIVER_NAME));
|
|
|
|
SmartcardExtension->ReaderExtension->CardParameters.bStopBits=2;
|
|
SmartcardExtension->ReaderExtension->CardParameters.fSynchronousCard=FALSE;
|
|
SmartcardExtension->ReaderExtension->CardParameters.fInversRevers=FALSE;
|
|
SmartcardExtension->ReaderExtension->CardParameters.bClockFrequency=4;
|
|
SmartcardExtension->ReaderExtension->CardParameters.fT0Mode=FALSE;
|
|
SmartcardExtension->ReaderExtension->CardParameters.fT0Write=FALSE;
|
|
SmartcardExtension->ReaderExtension->fReadCIS = FALSE;
|
|
|
|
// reset the state machine of the reader
|
|
NTStatus = CMMOB_ResetReader (SmartcardExtension->ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitPowerOnCard;
|
|
|
|
if (CMMOB_CardInserted (SmartcardExtension->ReaderExtension)) {
|
|
|
|
//initialize Timer
|
|
KeInitializeTimer(&TimerWait);
|
|
|
|
//we have to differentiate between cold and warm reset
|
|
if (SmartcardExtension->MinorIoControlCode == SCARD_WARM_RESET &&
|
|
CMMOB_CardPowered (SmartcardExtension->ReaderExtension)) {
|
|
//warm reset
|
|
bPowerCmd=CMD_POWERON_WARM;
|
|
} else {
|
|
//cold reset
|
|
bPowerCmd=CMD_POWERON_COLD;
|
|
|
|
//if card is powerde we have to turn it off for cold reset
|
|
if (CMMOB_CardPowered (SmartcardExtension->ReaderExtension))
|
|
CMMOB_PowerOffCard (SmartcardExtension);
|
|
}
|
|
|
|
#define MAX_CARD_TYPE 2
|
|
|
|
for (ulCardType = 0; ulCardType < MAX_CARD_TYPE; ulCardType++) {
|
|
switch (ulCardType) {
|
|
case 0:
|
|
// BaudRate divider 372 - 1
|
|
SmartcardExtension->ReaderExtension->CardParameters.bBaudRateHigh = 0x01;
|
|
SmartcardExtension->ReaderExtension->CardParameters.bBaudRateLow = 0x73;
|
|
if (fMaxWaitTime)
|
|
lWaitTime=1000;
|
|
else
|
|
lWaitTime=100;
|
|
SmartcardDebug(DEBUG_ATR,
|
|
("%s!trying 3.57 Mhz smart card, waiting time %ims\n",DRIVER_NAME,lWaitTime));
|
|
break;
|
|
|
|
case 1:
|
|
// BaudRate divider 512 - 1
|
|
SmartcardExtension->ReaderExtension->CardParameters.bBaudRateHigh = 0x01;
|
|
SmartcardExtension->ReaderExtension->CardParameters.bBaudRateLow = 0xFF;
|
|
if (fMaxWaitTime)
|
|
lWaitTime=1400;
|
|
else
|
|
lWaitTime=140;
|
|
SmartcardDebug(DEBUG_ATR,
|
|
("%s!trying 4.92 Mhz smart card, waiting time %ims\n",DRIVER_NAME,lWaitTime));
|
|
break;
|
|
}
|
|
|
|
//set baud rate
|
|
NTStatus=CMMOB_SetCardParameters(SmartcardExtension->ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitPowerOnCard;
|
|
|
|
//issue power on command
|
|
NTStatus=CMMOB_WriteRegister(SmartcardExtension->ReaderExtension,
|
|
ADDR_WRITEREG_FLAGS0, bPowerCmd);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitPowerOnCard;
|
|
|
|
// maximum wait for power on first byte 100 ms
|
|
liWaitTime = RtlConvertLongToLargeInteger(100L * -10000L);
|
|
KeSetTimer(&TimerWait,liWaitTime,NULL);
|
|
do {
|
|
fTimeExpired = KeReadStateTimer(&TimerWait);
|
|
NTStatus=CMMOB_BytesReceived (SmartcardExtension->ReaderExtension,&ulBytesReceived);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitPowerOnCard;
|
|
// wait 1 ms, so that processor is not blocked
|
|
SysDelay(1);
|
|
}
|
|
while (fTimeExpired==FALSE && ulBytesReceived == 0x00);
|
|
|
|
if (fTimeExpired) {
|
|
NTStatus = STATUS_IO_TIMEOUT;
|
|
} else {
|
|
ULONG ulBytesReceivedPrevious;
|
|
|
|
KeCancelTimer(&TimerWait);
|
|
|
|
// maximum wait for power on last byte 1 s for 3.58 card
|
|
// and 1.4 seconds for 4.91 cards
|
|
liWaitTime = RtlConvertLongToLargeInteger(lWaitTime * -10000L);
|
|
do {
|
|
KeSetTimer(&TimerWait,liWaitTime,NULL);
|
|
NTStatus=CMMOB_BytesReceived (SmartcardExtension->ReaderExtension,&ulBytesReceivedPrevious);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitPowerOnCard;
|
|
do {
|
|
fTimeExpired = KeReadStateTimer(&TimerWait);
|
|
NTStatus=CMMOB_BytesReceived (SmartcardExtension->ReaderExtension,&ulBytesReceived);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitPowerOnCard;
|
|
// wait 1 ms, so that processor is not blocked
|
|
SysDelay(1);
|
|
}
|
|
while (fTimeExpired==FALSE && ulBytesReceivedPrevious == ulBytesReceived);
|
|
|
|
if (!fTimeExpired) {
|
|
KeCancelTimer(&TimerWait);
|
|
}
|
|
}
|
|
while (!fTimeExpired);
|
|
|
|
|
|
//now we should have received an ATR
|
|
NTStatus=CMMOB_ResetReader (SmartcardExtension->ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitPowerOnCard;
|
|
|
|
NTStatus=CMMOB_ReadBuffer(SmartcardExtension->ReaderExtension, 0, 1, &bFirstByte);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitPowerOnCard;
|
|
|
|
if ((bFirstByte != 0x3B &&
|
|
bFirstByte != 0x03 )||
|
|
ulBytesReceived > MAXIMUM_ATR_LENGTH) {
|
|
NTStatus=STATUS_UNRECOGNIZED_MEDIA;
|
|
} else {
|
|
pbATR[0]=bFirstByte;
|
|
NTStatus=CMMOB_ReadBuffer(SmartcardExtension->ReaderExtension,
|
|
1, ulBytesReceived, &pbATR[1]);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitPowerOnCard;
|
|
*pulATRLength = ulBytesReceived;
|
|
// success leave the loop
|
|
break;
|
|
}
|
|
}
|
|
// if not the last time in the loop power off
|
|
// the card to get a well defined condition
|
|
// (after the last pass the power off is
|
|
// done outside the loop if necessary)
|
|
if (ulCardType < MAX_CARD_TYPE-1) {
|
|
CMMOB_PowerOffCard(SmartcardExtension);
|
|
}
|
|
}
|
|
} else {
|
|
NTStatus=STATUS_NO_MEDIA;
|
|
}
|
|
|
|
ExitPowerOnCard:
|
|
|
|
if (NTStatus!=STATUS_SUCCESS) {
|
|
if (NTStatus != STATUS_NO_MEDIA) {
|
|
NTStatus = STATUS_UNRECOGNIZED_MEDIA;
|
|
}
|
|
CMMOB_PowerOffCard(SmartcardExtension);
|
|
}
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!PowerOnCard: Exit %lx\n",DRIVER_NAME,NTStatus));
|
|
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Routine Description:
|
|
CMMOB_PowerOffCard
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
*****************************************************************************/
|
|
NTSTATUS CMMOB_PowerOffCard (
|
|
IN PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
BYTE* pbRegsBase;
|
|
KTIMER TimerWait;
|
|
LARGE_INTEGER liWaitTime;
|
|
BOOLEAN fTimeExpired;
|
|
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!PowerOffCard: Enter\n",DRIVER_NAME));
|
|
|
|
NTStatus = CMMOB_ResetReader (SmartcardExtension->ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitPowerOffCard;
|
|
|
|
pbRegsBase=SmartcardExtension->ReaderExtension->pbRegsBase;
|
|
if (CMMOB_CardInserted (SmartcardExtension->ReaderExtension)) {
|
|
// set card state for update thread
|
|
// otherwise a card removal/insertion would be recognized
|
|
if (SmartcardExtension->ReaderExtension->ulOldCardState == POWERED)
|
|
SmartcardExtension->ReaderExtension->ulOldCardState = INSERTED;
|
|
|
|
//issue power off command
|
|
CMMOB_WriteRegister(SmartcardExtension->ReaderExtension,
|
|
ADDR_WRITEREG_FLAGS0, CMD_POWEROFF);
|
|
|
|
KeInitializeTimer(&TimerWait);
|
|
// maximum wait for power down 1 second
|
|
liWaitTime = RtlConvertLongToLargeInteger(1000L * -10000L);
|
|
KeSetTimer(&TimerWait,liWaitTime,NULL);
|
|
do {
|
|
fTimeExpired = KeReadStateTimer(&TimerWait);
|
|
// wait 1 ms, so that processor is not blocked
|
|
SysDelay(1);
|
|
}
|
|
while (fTimeExpired==FALSE && CMMOB_CardPowered (SmartcardExtension->ReaderExtension));
|
|
|
|
if (fTimeExpired) {
|
|
NTStatus = STATUS_IO_TIMEOUT;
|
|
} else {
|
|
KeCancelTimer(&TimerWait);
|
|
}
|
|
} else {
|
|
NTStatus=STATUS_NO_MEDIA;
|
|
}
|
|
|
|
ExitPowerOffCard:
|
|
|
|
CMMOB_ResetReader (SmartcardExtension->ReaderExtension);
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!PowerOffCard: Exit %lx\n",DRIVER_NAME,NTStatus));
|
|
|
|
return NTStatus;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
CMMOB_SetProtocol:
|
|
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 CMMOB_SetProtocol(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus;
|
|
PREADER_EXTENSION ReaderExtension;
|
|
USHORT usSCLibProtocol;
|
|
UCHAR abPTSRequest[4];
|
|
UCHAR abPTSReply [4];
|
|
ULONG ulBytesRead;
|
|
ULONG ulBaudRateDivider;
|
|
ULONG ulWaitTime;
|
|
UCHAR bTemp;
|
|
ULONG i;
|
|
KIRQL irql;
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!SetProtocol: Enter\n",DRIVER_NAME ));
|
|
|
|
ReaderExtension = SmartcardExtension->ReaderExtension;
|
|
|
|
|
|
ReaderExtension->fTActive=TRUE;
|
|
NTStatus = CMMOB_SetFlags1(ReaderExtension);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
goto ExitSetProtocol;
|
|
}
|
|
|
|
|
|
NTStatus = STATUS_PENDING;
|
|
|
|
usSCLibProtocol = ( USHORT )( SmartcardExtension->MinorIoControlCode );
|
|
|
|
//
|
|
// check card insertion
|
|
//
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
if (SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_ABSENT) {
|
|
NTStatus = STATUS_NO_MEDIA;
|
|
} else {
|
|
//
|
|
// Check if the card is already in specific state and if the caller
|
|
// wants to have the selected protocol
|
|
//
|
|
if (SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC) {
|
|
if (SmartcardExtension->CardCapabilities.Protocol.Selected == usSCLibProtocol) {
|
|
NTStatus = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
if (NTStatus == STATUS_PENDING) {
|
|
|
|
//
|
|
// reset the state machine of the reader
|
|
//
|
|
NTStatus=CMMOB_ResetReader(ReaderExtension);
|
|
if (NTStatus==STATUS_SUCCESS) {
|
|
// try 2 times,
|
|
// 0 - optimal
|
|
// 1 - default
|
|
for (i=0; i<2; i++) {
|
|
|
|
// set initial character of PTS
|
|
abPTSRequest[0] = 0xFF;
|
|
|
|
// set the format character (PTS0)
|
|
if (SmartcardExtension->CardCapabilities.Protocol.Supported &
|
|
usSCLibProtocol & SCARD_PROTOCOL_T1) {
|
|
// select T=1 and indicate that PTS1 follows
|
|
abPTSRequest[1] = 0x11;
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T1;
|
|
} else if (SmartcardExtension->CardCapabilities.Protocol.Supported &
|
|
usSCLibProtocol & SCARD_PROTOCOL_T0) {
|
|
// select T=0 and indicate that PTS1 follows
|
|
abPTSRequest[1] = 0x10;
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T0;
|
|
} else {
|
|
// we do not support other protocols
|
|
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto ExitSetProtocol;
|
|
}
|
|
|
|
|
|
if (i==0) {
|
|
// optimal
|
|
bTemp = (BYTE) (SmartcardExtension->CardCapabilities.PtsData.Fl << 4 |
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl);
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s! from library suggested PTS1(0x%x)\n",DRIVER_NAME,bTemp));
|
|
|
|
SmartcardExtension->CardCapabilities.PtsData.Type = PTS_TYPE_OPTIMAL;
|
|
SmartcardExtension->CardCapabilities.PtsData.Fl=SmartcardExtension->CardCapabilities.Fl;
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl=SmartcardExtension->CardCapabilities.Dl;
|
|
} else {
|
|
// default
|
|
// we don´t know if it is correct to set 4.91Mhz cards to 0x11
|
|
// but we have no card to try now
|
|
SmartcardExtension->CardCapabilities.PtsData.Type = PTS_TYPE_DEFAULT;
|
|
SmartcardExtension->CardCapabilities.PtsData.Fl=1;
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl=1;
|
|
}
|
|
|
|
bTemp = (BYTE) (SmartcardExtension->CardCapabilities.PtsData.Fl << 4 |
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl);
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s! trying PTS1(0x%x)\n",DRIVER_NAME,bTemp));
|
|
switch (SmartcardExtension->CardCapabilities.PtsData.Fl) {
|
|
case 1:
|
|
// here we can handle all baudrates
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
if (SmartcardExtension->CardCapabilities.PtsData.Dl == 1) {
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s! overwriting PTS1(0x%x)\n",DRIVER_NAME,bTemp));
|
|
// we must correct Fl/Dl
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl = 0x01;
|
|
SmartcardExtension->CardCapabilities.PtsData.Fl = 0x01;
|
|
}
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
if (SmartcardExtension->CardCapabilities.PtsData.Dl == 1 ||
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl == 2) {
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s! overwriting PTS1(0x%x)\n",DRIVER_NAME,bTemp));
|
|
// we must correct Fl/Dl
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl = 0x01;
|
|
SmartcardExtension->CardCapabilities.PtsData.Fl = 0x01;
|
|
}
|
|
break;
|
|
case 9:
|
|
// here we can handle all baudrates
|
|
break;
|
|
case 10:
|
|
case 11:
|
|
if (SmartcardExtension->CardCapabilities.PtsData.Dl == 1) {
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s! overwriting PTS1(0x%x)\n",DRIVER_NAME,bTemp));
|
|
// we must correct Fl/Dl
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl = 0x01;
|
|
SmartcardExtension->CardCapabilities.PtsData.Fl = 0x09;
|
|
}
|
|
break;
|
|
case 12:
|
|
case 13:
|
|
if (SmartcardExtension->CardCapabilities.PtsData.Dl == 1 ||
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl == 2) {
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s! overwriting PTS1(0x%x)\n",DRIVER_NAME,bTemp));
|
|
// we must correct Fl/Dl
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl = 0x01;
|
|
SmartcardExtension->CardCapabilities.PtsData.Fl = 0x09;
|
|
}
|
|
break;
|
|
default:
|
|
// this are the RFUs
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s! overwriting PTS1(0x%x)\n",DRIVER_NAME,bTemp));
|
|
// we must correct Fl/Dl
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl = 0x01;
|
|
SmartcardExtension->CardCapabilities.PtsData.Fl = 0x01;
|
|
break;
|
|
}
|
|
|
|
|
|
// set PTS1 with codes Fl and Dl
|
|
abPTSRequest[2] = (BYTE) (SmartcardExtension->CardCapabilities.PtsData.Fl << 4 |
|
|
SmartcardExtension->CardCapabilities.PtsData.Dl);
|
|
|
|
|
|
// set PCK (check character)
|
|
abPTSRequest[3] = (BYTE)(abPTSRequest[0] ^ abPTSRequest[1] ^ abPTSRequest[2]);
|
|
|
|
if (ReaderExtension->CardParameters.fInversRevers) {
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s! PTS request for InversConvention\n",DRIVER_NAME));
|
|
CMMOB_InverseBuffer (abPTSRequest,4);
|
|
}
|
|
|
|
#if DBG
|
|
{
|
|
ULONG k;
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%s! writing PTS request: ",DRIVER_NAME));
|
|
for (k = 0;k < 4;k++)
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%2.2x ",abPTSRequest[k]));
|
|
SmartcardDebug(DEBUG_PROTOCOL,("\n"));
|
|
}
|
|
#endif
|
|
|
|
NTStatus = CMMOB_WriteT1(ReaderExtension,4,abPTSRequest);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
SmartcardDebug(DEBUG_ERROR,
|
|
("%s! writing PTS request failed\n", DRIVER_NAME));
|
|
goto ExitSetProtocol;
|
|
}
|
|
|
|
// read back PTS data
|
|
ulWaitTime=1000;
|
|
if (SmartcardExtension->CardCapabilities.PtsData.Fl >= 8)
|
|
ulWaitTime=1400;
|
|
NTStatus = CMMOB_ReadT1(ReaderExtension,4,
|
|
ulWaitTime,ulWaitTime,
|
|
abPTSReply,&ulBytesRead);
|
|
// in case of an short PTS reply an timeout will occur,
|
|
// but that's not the standard case
|
|
if (NTStatus != STATUS_SUCCESS && NTStatus != STATUS_IO_TIMEOUT) {
|
|
SmartcardDebug(DEBUG_ERROR,
|
|
("%s! reading PTS reply: failed\n",DRIVER_NAME));
|
|
goto ExitSetProtocol;
|
|
}
|
|
#if DBG
|
|
{
|
|
ULONG k;
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%s! reading PTS reply: ",DRIVER_NAME));
|
|
for (k = 0;k < ulBytesRead;k++)
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%2.2x ",abPTSReply[k]));
|
|
SmartcardDebug(DEBUG_PROTOCOL,("\n"));
|
|
}
|
|
#endif
|
|
|
|
if (ulBytesRead == 4 &&
|
|
abPTSReply[0] == abPTSRequest[0] &&
|
|
abPTSReply[1] == abPTSRequest[1] &&
|
|
abPTSReply[2] == abPTSRequest[2] &&
|
|
abPTSReply[3] == abPTSRequest[3] ) {
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s! PTS request and reply match\n",DRIVER_NAME));
|
|
|
|
if ((SmartcardExtension->CardCapabilities.PtsData.Fl >= 3 &&
|
|
SmartcardExtension->CardCapabilities.PtsData.Fl < 8) ||
|
|
(SmartcardExtension->CardCapabilities.PtsData.Fl >= 11 &&
|
|
SmartcardExtension->CardCapabilities.PtsData.Fl < 16)) {
|
|
ReaderExtension->CardParameters.bClockFrequency=8;
|
|
}
|
|
|
|
ulBaudRateDivider = Fi[SmartcardExtension->CardCapabilities.PtsData.Fl] /
|
|
Di[SmartcardExtension->CardCapabilities.PtsData.Dl];
|
|
// decrease by 1, because these values have to be written to CardMan
|
|
ulBaudRateDivider--;
|
|
if (ulBaudRateDivider < 512) {
|
|
ReaderExtension->CardParameters.bBaudRateLow=(UCHAR)(ulBaudRateDivider & 0xFF);
|
|
if (ulBaudRateDivider>255) {
|
|
ReaderExtension->CardParameters.bBaudRateHigh=1;
|
|
} else {
|
|
ReaderExtension->CardParameters.bBaudRateHigh=0;
|
|
}
|
|
|
|
NTStatus = CMMOB_SetCardParameters (ReaderExtension);
|
|
if (NTStatus == STATUS_SUCCESS) {
|
|
//
|
|
// we had success, leave the loop
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ulBytesRead == 3 &&
|
|
abPTSReply[0] == abPTSRequest[0] &&
|
|
(abPTSReply[1] & 0x7F) == (abPTSRequest[1] & 0x0F) &&
|
|
abPTSReply[2] == (BYTE)(abPTSReply[0] ^ abPTSReply[1] )) {
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s! Short PTS reply received\n",DRIVER_NAME));
|
|
|
|
if (SmartcardExtension->CardCapabilities.PtsData.Fl >= 9) {
|
|
ulBaudRateDivider = 512;
|
|
} else {
|
|
ulBaudRateDivider = 372;
|
|
}
|
|
// decrease by 1, because these values have to be written to CardMan
|
|
ulBaudRateDivider--;
|
|
|
|
NTStatus = CMMOB_SetCardParameters (ReaderExtension);
|
|
if (NTStatus == STATUS_SUCCESS) {
|
|
//
|
|
// we had success, leave the loop
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i==0) {
|
|
// this was the first try
|
|
// we have a second with default values
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s! PTS failed : Trying default parameters\n",DRIVER_NAME));
|
|
|
|
// the card did either not reply or it replied incorrectly
|
|
// so try default values
|
|
SmartcardExtension->MinorIoControlCode = SCARD_COLD_RESET;
|
|
NTStatus = CMMOB_CardPower(SmartcardExtension);
|
|
} else {
|
|
// the card failed the PTS request
|
|
NTStatus = STATUS_DEVICE_PROTOCOL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ExitSetProtocol:
|
|
|
|
//
|
|
// if protocol selection failed, prevent from calling invalid protocols
|
|
//
|
|
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
if (NTStatus==STATUS_SUCCESS) {
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC;
|
|
} else {
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
|
|
}
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
|
|
//
|
|
// Return the selected protocol to the caller.
|
|
//
|
|
*(PULONG) (SmartcardExtension->IoRequest.ReplyBuffer) = SmartcardExtension->CardCapabilities.Protocol.Selected;
|
|
*SmartcardExtension->IoRequest.Information = sizeof( ULONG );
|
|
|
|
|
|
ReaderExtension->fTActive=FALSE;
|
|
CMMOB_SetFlags1(ReaderExtension);
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!SetProtocol: Exit %X\n",DRIVER_NAME,NTStatus ));
|
|
|
|
return( NTStatus );
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_Transmit:
|
|
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 CMMOB_Transmit (
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!Transmit: Enter\n",DRIVER_NAME ));
|
|
//
|
|
// dispatch on the selected protocol
|
|
//
|
|
switch (SmartcardExtension->CardCapabilities.Protocol.Selected) {
|
|
case SCARD_PROTOCOL_T0:
|
|
NTStatus = CMMOB_TransmitT0(SmartcardExtension);
|
|
break;
|
|
|
|
case SCARD_PROTOCOL_T1:
|
|
NTStatus = CMMOB_TransmitT1(SmartcardExtension);
|
|
break;
|
|
|
|
/*
|
|
case SCARD_PROTOCOL_RAW:
|
|
break;
|
|
*/
|
|
|
|
default:
|
|
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!Transmit: Exit %X\n",DRIVER_NAME,NTStatus ));
|
|
|
|
return( NTStatus );
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_TransmitT0:
|
|
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 CMMOB_TransmitT0 (
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus;
|
|
UCHAR abWriteBuffer[MIN_BUFFER_SIZE];
|
|
UCHAR abReadBuffer[MIN_BUFFER_SIZE];
|
|
ULONG ulBytesToWrite; //length written to card
|
|
ULONG ulBytesToReceive; //length expected from card
|
|
ULONG ulBytesToRead; //length expected from reader
|
|
ULONG ulBytesRead; //length received from reader
|
|
//(without length written)
|
|
ULONG ulCWTWaitTime;
|
|
BOOLEAN fDataSent; //data longer than T0_HEADER
|
|
|
|
|
|
SmartcardExtension->ReaderExtension->fTActive=TRUE;
|
|
NTStatus = CMMOB_SetFlags1(SmartcardExtension->ReaderExtension);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
goto ExitTransmitT0;
|
|
}
|
|
|
|
|
|
// reset the state machine of the reader
|
|
NTStatus = CMMOB_ResetReader (SmartcardExtension->ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS) {
|
|
// there must be severe error
|
|
goto ExitTransmitT0;
|
|
}
|
|
|
|
// set T0 mode
|
|
SmartcardExtension->ReaderExtension->CardParameters.fT0Mode=TRUE;
|
|
|
|
// increase timeout for T0 Transmission
|
|
ulCWTWaitTime = SmartcardExtension->CardCapabilities.T0.WT/1000 + 1500;
|
|
|
|
|
|
//
|
|
// Let the lib build a T=0 packet
|
|
//
|
|
|
|
// no bytes additionally needed
|
|
SmartcardExtension->SmartcardRequest.BufferLength = 0;
|
|
NTStatus = SmartcardT0Request(SmartcardExtension);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
// the lib detected an error in the data to send.
|
|
goto ExitTransmitT0;
|
|
}
|
|
|
|
// copy data to the write buffer
|
|
ulBytesToWrite = T0_HEADER_LEN + SmartcardExtension->T0.Lc;
|
|
RtlCopyMemory(abWriteBuffer,SmartcardExtension->SmartcardRequest.Buffer,ulBytesToWrite);
|
|
ulBytesToReceive = SmartcardExtension->T0.Le;
|
|
|
|
#if DBG
|
|
{
|
|
ULONG i;
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%s!TransmitT0: Request ",DRIVER_NAME));
|
|
for (i = 0;i < ulBytesToWrite;i++)
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%2.2x ",abWriteBuffer[i]));
|
|
SmartcardDebug(DEBUG_PROTOCOL,("\n"));
|
|
}
|
|
#endif
|
|
|
|
// set T0 write flag correctly
|
|
if (ulBytesToReceive == 0) {
|
|
SmartcardExtension->ReaderExtension->CardParameters.fT0Write=TRUE;
|
|
} else {
|
|
SmartcardExtension->ReaderExtension->CardParameters.fT0Write=FALSE;
|
|
}
|
|
NTStatus=CMMOB_SetCardParameters(SmartcardExtension->ReaderExtension);
|
|
if (NTStatus != STATUS_SUCCESS)
|
|
goto ExitTransmitT0;
|
|
|
|
|
|
NTStatus = CMMOB_WriteT0 (SmartcardExtension->ReaderExtension,
|
|
ulBytesToWrite,
|
|
ulBytesToReceive,
|
|
abWriteBuffer);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
goto ExitTransmitT0;
|
|
}
|
|
|
|
// bytes to write + answer + SW2
|
|
if ( (MAXULONG - ulBytesToWrite < ulBytesToReceive + 1) ||
|
|
(ulBytesToReceive == MAXULONG)) {
|
|
NTStatus = STATUS_BUFFER_OVERFLOW;
|
|
goto ExitTransmitT0;
|
|
}
|
|
ulBytesToRead = ulBytesToWrite + ulBytesToReceive + 1;
|
|
|
|
if (ulBytesToRead > MIN_BUFFER_SIZE) {
|
|
NTStatus = STATUS_BUFFER_OVERFLOW;
|
|
goto ExitTransmitT0;
|
|
}
|
|
NTStatus = CMMOB_ReadT0 (SmartcardExtension->ReaderExtension,
|
|
ulBytesToRead,
|
|
ulBytesToWrite,
|
|
ulCWTWaitTime,
|
|
abReadBuffer,
|
|
&ulBytesRead,
|
|
&fDataSent);
|
|
|
|
#if DBG
|
|
{
|
|
ULONG i;
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%s!TransmitT0: Reply ",DRIVER_NAME));
|
|
for (i = 0;i < ulBytesRead;i++)
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%2.2x ",abReadBuffer[i]));
|
|
SmartcardDebug(DEBUG_PROTOCOL,("\n"));
|
|
}
|
|
#endif
|
|
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%s!TransmitT0: Read failed!\n",DRIVER_NAME));
|
|
goto ExitTransmitT0;
|
|
}
|
|
|
|
// copy received bytes
|
|
if (ulBytesRead <= SmartcardExtension->SmartcardReply.BufferSize) {
|
|
RtlCopyBytes((PVOID)SmartcardExtension->SmartcardReply.Buffer,
|
|
(PVOID) abReadBuffer,
|
|
ulBytesRead);
|
|
SmartcardExtension->SmartcardReply.BufferLength = ulBytesRead;
|
|
} else {
|
|
NTStatus=STATUS_BUFFER_OVERFLOW;
|
|
goto ExitTransmitT0;
|
|
}
|
|
|
|
// let the lib copy the received bytes to the user buffer
|
|
NTStatus = SmartcardT0Reply(SmartcardExtension);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
goto ExitTransmitT0;
|
|
}
|
|
|
|
|
|
ExitTransmitT0:
|
|
// ------------------------------------------
|
|
// ITSEC E2 requirements: clear write buffers
|
|
// ------------------------------------------
|
|
RtlFillMemory((PVOID)abWriteBuffer,sizeof(abWriteBuffer),0x00);
|
|
RtlFillMemory((PVOID)SmartcardExtension->SmartcardRequest.Buffer,
|
|
SmartcardExtension->SmartcardRequest.BufferSize,0x00);
|
|
|
|
// set T0 mode back
|
|
SmartcardExtension->ReaderExtension->CardParameters.fT0Mode=FALSE;
|
|
SmartcardExtension->ReaderExtension->CardParameters.fT0Write=FALSE;
|
|
CMMOB_SetCardParameters(SmartcardExtension->ReaderExtension);
|
|
|
|
|
|
SmartcardExtension->ReaderExtension->fTActive=FALSE;
|
|
CMMOB_SetFlags1(SmartcardExtension->ReaderExtension);
|
|
|
|
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_TransmitT1:
|
|
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 CMMOB_TransmitT1 (
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus;
|
|
UCHAR abReadBuffer[CMMOB_MAXBUFFER];
|
|
LONG lBytesToRead;
|
|
ULONG ulBytesRead;
|
|
ULONG ulCurrentWaitTime;
|
|
ULONG ulCWTWaitTime;
|
|
ULONG ulBWTWaitTime;
|
|
ULONG ulWTXWaitTime;
|
|
ULONG ulTemp;
|
|
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s!TransmitT1 CWT = %ld(ms)\n",DRIVER_NAME,
|
|
SmartcardExtension->CardCapabilities.T1.CWT/1000));
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s!TransmitT1 BWT = %ld(ms)\n",DRIVER_NAME,
|
|
SmartcardExtension->CardCapabilities.T1.BWT/1000));
|
|
|
|
ulCWTWaitTime = (ULONG)(100 + 32*(SmartcardExtension->CardCapabilities.T1.CWT/1000));
|
|
ulBWTWaitTime = (ULONG)(1000 + SmartcardExtension->CardCapabilities.T1.BWT/1000);
|
|
ulWTXWaitTime = 0;
|
|
|
|
|
|
SmartcardExtension->ReaderExtension->fTActive=TRUE;
|
|
NTStatus = CMMOB_SetFlags1(SmartcardExtension->ReaderExtension);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
goto ExitTransmitT1;
|
|
}
|
|
|
|
|
|
// reset the state machine of the reader
|
|
NTStatus = CMMOB_ResetReader (SmartcardExtension->ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS) {
|
|
// there must be severe error
|
|
goto ExitTransmitT1;
|
|
}
|
|
|
|
do {
|
|
// no bytes additionally needed
|
|
SmartcardExtension->SmartcardRequest.BufferLength = 0;
|
|
|
|
NTStatus = SmartcardT1Request(SmartcardExtension);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
// this should never happen, so we return immediately
|
|
goto ExitTransmitT1;
|
|
}
|
|
|
|
#if DBG
|
|
{
|
|
ULONG i;
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%s!TransmitT1: Request ",DRIVER_NAME));
|
|
for (i = 0;i < SmartcardExtension->SmartcardRequest.BufferLength;i++)
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%2.2x ",SmartcardExtension->SmartcardRequest.Buffer[i]));
|
|
SmartcardDebug(DEBUG_PROTOCOL,("\n"));
|
|
}
|
|
#endif
|
|
|
|
// write to the reader
|
|
NTStatus = CMMOB_WriteT1 (SmartcardExtension->ReaderExtension,
|
|
SmartcardExtension->SmartcardRequest.BufferLength,
|
|
SmartcardExtension->SmartcardRequest.Buffer);
|
|
if (NTStatus == STATUS_SUCCESS) {
|
|
|
|
if (ulWTXWaitTime == 0 ) { // use BWT
|
|
/*
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!ulCurrentWaitTime = %ld\n",DRIVER_NAME,ulCurrentWaitTime));
|
|
*/
|
|
ulCurrentWaitTime = ulBWTWaitTime;
|
|
} else { // use WTX time
|
|
/*
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!ulCurrentWaitTime = %ld\n",DRIVER_NAME,ulWTXWaitTime));
|
|
*/
|
|
ulCurrentWaitTime = ulWTXWaitTime;
|
|
}
|
|
|
|
|
|
if (SmartcardExtension->CardCapabilities.T1.EDC == T1_CRC_CHECK) {
|
|
// in case of card with CRC check read reply + 5 bytes
|
|
// a negative value indicates a relative number of bytes to read
|
|
lBytesToRead=-5;
|
|
} else {
|
|
// in case of card with CRC check read reply + 4 bytes
|
|
// a negative value indicates a relative number of bytes to read
|
|
lBytesToRead=-4;
|
|
}
|
|
|
|
NTStatus = CMMOB_ReadT1(SmartcardExtension->ReaderExtension,lBytesToRead,
|
|
ulCurrentWaitTime,ulCWTWaitTime,abReadBuffer,&ulBytesRead);
|
|
if (NTStatus == STATUS_SUCCESS) {
|
|
|
|
if (abReadBuffer[1] == T1_WTX_REQUEST) {
|
|
ulWTXWaitTime = (ULONG)(1000 +((SmartcardExtension->CardCapabilities.T1.BWT*abReadBuffer[3])/1000));
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s!TransmitT1 WTX = %ld(ms)\n",DRIVER_NAME,ulWTXWaitTime));
|
|
} else {
|
|
ulWTXWaitTime = 0;
|
|
}
|
|
|
|
#if DBG
|
|
{
|
|
ULONG i;
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%s!TransmitT1: Reply ",DRIVER_NAME));
|
|
for (i = 0;i < ulBytesRead;i++)
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%2.2x ",abReadBuffer[i]));
|
|
SmartcardDebug(DEBUG_PROTOCOL,("\n"));
|
|
}
|
|
#endif
|
|
// copy received bytes
|
|
if (ulBytesRead <= SmartcardExtension->SmartcardReply.BufferSize) {
|
|
RtlCopyBytes((PVOID)SmartcardExtension->SmartcardReply.Buffer,
|
|
(PVOID)abReadBuffer,
|
|
ulBytesRead);
|
|
SmartcardExtension->SmartcardReply.BufferLength = ulBytesRead;
|
|
} else {
|
|
NTStatus=STATUS_BUFFER_OVERFLOW;
|
|
goto ExitTransmitT1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
SmartcardExtension->SmartcardReply.BufferLength = 0L;
|
|
}
|
|
|
|
// bug fix for smclib
|
|
if (SmartcardExtension->T1.State == T1_IFS_RESPONSE &&
|
|
SmartcardExtension->T1.OriginalState == T1_I_BLOCK) {
|
|
SmartcardExtension->T1.State = T1_I_BLOCK;
|
|
}
|
|
|
|
NTStatus = SmartcardT1Reply(SmartcardExtension);
|
|
}
|
|
while (NTStatus == STATUS_MORE_PROCESSING_REQUIRED);
|
|
|
|
|
|
ExitTransmitT1:
|
|
// ------------------------------------------
|
|
// ITSEC E2 requirements: clear write buffers
|
|
// ------------------------------------------
|
|
RtlFillMemory((PVOID)SmartcardExtension->SmartcardRequest.Buffer,
|
|
SmartcardExtension->SmartcardRequest.BufferSize,0x00);
|
|
|
|
SmartcardExtension->ReaderExtension->fTActive=FALSE;
|
|
CMMOB_SetFlags1(SmartcardExtension->ReaderExtension);
|
|
|
|
return NTStatus;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
CMMOB_IoCtlVendor:
|
|
Performs generic callbacks to the reader
|
|
|
|
Arguments:
|
|
SmartcardExtension context of the call
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_IoCtlVendor(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus=STATUS_SUCCESS;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IrpStack;
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!IoCtlVendor: Enter\n",DRIVER_NAME ));
|
|
|
|
//
|
|
// get pointer to current IRP stack location
|
|
//
|
|
Irp = SmartcardExtension->OsData->CurrentIrp;
|
|
IrpStack = IoGetCurrentIrpStackLocation( Irp );
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
//
|
|
// dispatch IOCTL
|
|
//
|
|
switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
|
|
case CM_IOCTL_GET_FW_VERSION:
|
|
NTStatus = CMMOB_GetFWVersion(SmartcardExtension);
|
|
break;
|
|
|
|
case CM_IOCTL_CR80S_SAMOS_SET_HIGH_SPEED:
|
|
NTStatus = CMMOB_SetHighSpeed_CR80S_SAMOS(SmartcardExtension);
|
|
break;
|
|
|
|
case CM_IOCTL_SET_READER_9600_BAUD:
|
|
NTStatus = CMMOB_SetReader_9600Baud(SmartcardExtension);
|
|
break;
|
|
|
|
case CM_IOCTL_SET_READER_38400_BAUD:
|
|
NTStatus = CMMOB_SetReader_38400Baud(SmartcardExtension);
|
|
break;
|
|
|
|
case CM_IOCTL_READ_DEVICE_DESCRIPTION:
|
|
NTStatus = CMMOB_ReadDeviceDescription(SmartcardExtension);
|
|
break;
|
|
|
|
default:
|
|
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// set NTStatus of the packet
|
|
//
|
|
Irp->IoStatus.Status = NTStatus;
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!IoCtlVendor: Exit %X\n",DRIVER_NAME,NTStatus ));
|
|
|
|
return( NTStatus );
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value: STATUS_UNSUCCESSFUL
|
|
STATUS_SUCCESS
|
|
|
|
*****************************************************************************/
|
|
NTSTATUS CMMOB_SetReader_9600Baud (
|
|
IN PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
KIRQL irql;
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!SetReader_9600Baud: Enter\n",DRIVER_NAME));
|
|
|
|
// check if card is already in specific mode
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
if (SmartcardExtension->ReaderCapabilities.CurrentState != SCARD_SPECIFIC) {
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto ExitSetReader9600;
|
|
}
|
|
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
// set 9600 Baud for 3.58 MHz
|
|
SmartcardExtension->ReaderExtension->CardParameters.bBaudRateHigh=0x01;
|
|
SmartcardExtension->ReaderExtension->CardParameters.bBaudRateLow=0x73;
|
|
NTStatus = CMMOB_SetCardParameters (SmartcardExtension->ReaderExtension);
|
|
|
|
ExitSetReader9600:
|
|
*SmartcardExtension->IoRequest.Information = 0L;
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!SetReader_9600Baud: Exit %lx\n",DRIVER_NAME,NTStatus));
|
|
|
|
return(NTStatus);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value: STATUS_UNSUCCESSFUL
|
|
STATUS_SUCCESS
|
|
|
|
*****************************************************************************/
|
|
NTSTATUS CMMOB_SetReader_38400Baud (
|
|
IN PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
KIRQL irql;
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!SetReader_38400Baud: Enter\n",DRIVER_NAME));
|
|
|
|
// check if card is already in specific mode
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
if (SmartcardExtension->ReaderCapabilities.CurrentState != SCARD_SPECIFIC) {
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto ExitSetReader38400;
|
|
}
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
|
|
// set 384000 Baud for 3.58 MHz card
|
|
SmartcardExtension->ReaderExtension->CardParameters.bBaudRateHigh=0x00;
|
|
SmartcardExtension->ReaderExtension->CardParameters.bBaudRateLow=0x5D;
|
|
NTStatus = CMMOB_SetCardParameters (SmartcardExtension->ReaderExtension);
|
|
|
|
ExitSetReader38400:
|
|
*SmartcardExtension->IoRequest.Information = 0L;
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!SetReader_38400Baud: Exit %lx\n",DRIVER_NAME,NTStatus));
|
|
|
|
return(NTStatus);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value: STATUS_UNSUCCESSFUL
|
|
STATUS_SUCCESS
|
|
|
|
*****************************************************************************/
|
|
NTSTATUS CMMOB_SetHighSpeed_CR80S_SAMOS (
|
|
IN PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus;
|
|
UCHAR abCR80S_SAMOS_SET_HIGH_SPEED[4] = {0xFF,0x11,0x94,0x7A};
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!SetHighSpeed_CR80S_SAMOS: Enter\n",DRIVER_NAME));
|
|
|
|
NTStatus = CMMOB_SetSpeed (SmartcardExtension,
|
|
abCR80S_SAMOS_SET_HIGH_SPEED);
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!SetHighSpeed_CR80S_SAMOS: Exit %lx\n",DRIVER_NAME,NTStatus));
|
|
|
|
return(NTStatus);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value: STATUS_UNSUCCESSFUL
|
|
STATUS_SUCCESS
|
|
|
|
*****************************************************************************/
|
|
NTSTATUS CMMOB_SetSpeed (
|
|
IN PSMARTCARD_EXTENSION SmartcardExtension,
|
|
IN PUCHAR abFIDICommand
|
|
)
|
|
{
|
|
NTSTATUS NTStatus;
|
|
NTSTATUS DebugStatus;
|
|
UCHAR abReadBuffer[16];
|
|
ULONG ulBytesRead;
|
|
ULONG ulWaitTime;
|
|
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!SetSpeed: Enter\n",DRIVER_NAME));
|
|
|
|
|
|
SmartcardExtension->ReaderExtension->fTActive=TRUE;
|
|
NTStatus = CMMOB_SetFlags1(SmartcardExtension->ReaderExtension);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
goto ExitSetSpeed;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
{
|
|
ULONG k;
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%s!SetSpeed: writing: ",DRIVER_NAME));
|
|
for (k = 0;k < 4;k++)
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%2.2x ",abFIDICommand[k]));
|
|
SmartcardDebug(DEBUG_PROTOCOL,("\n"));
|
|
}
|
|
#endif
|
|
|
|
NTStatus = CMMOB_WriteT1(SmartcardExtension->ReaderExtension,4,
|
|
abFIDICommand);
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
SmartcardDebug(DEBUG_ERROR,
|
|
("%s!SetSpeed: writing high speed command failed\n",DRIVER_NAME));
|
|
goto ExitSetSpeed;
|
|
}
|
|
|
|
|
|
// read back pts data
|
|
// maximim initial waiting time is 9600 * etu
|
|
// clock divider of this card 512 => 1.4 sec is sufficient
|
|
ulWaitTime = 1400;
|
|
NTStatus = CMMOB_ReadT1(SmartcardExtension->ReaderExtension,4,
|
|
ulWaitTime,ulWaitTime,abReadBuffer,&ulBytesRead);
|
|
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s!SetSpeed: reading echo: ",DRIVER_NAME));
|
|
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
SmartcardDebug(DEBUG_PROTOCOL,("failed\n"));
|
|
goto ExitSetSpeed;
|
|
}
|
|
|
|
#if DBG
|
|
{
|
|
ULONG k;
|
|
for (k = 0;k < ulBytesRead;k++)
|
|
SmartcardDebug(DEBUG_PROTOCOL,("%2.2x ",abReadBuffer[k]));
|
|
SmartcardDebug(DEBUG_PROTOCOL,("\n"));
|
|
}
|
|
#endif
|
|
|
|
// if the card has accepted this string , the string is echoed
|
|
if (abReadBuffer[0] == abFIDICommand[0] &&
|
|
abReadBuffer[1] == abFIDICommand[1] &&
|
|
abReadBuffer[2] == abFIDICommand[2] &&
|
|
abReadBuffer[3] == abFIDICommand[3] ) {
|
|
SmartcardExtension->ReaderExtension->CardParameters.bBaudRateLow=63;
|
|
SmartcardExtension->ReaderExtension->CardParameters.bBaudRateHigh=0;
|
|
NTStatus = CMMOB_SetCardParameters (SmartcardExtension->ReaderExtension);
|
|
} else {
|
|
SmartcardExtension->MinorIoControlCode = SCARD_COLD_RESET;
|
|
CMMOB_CardPower(SmartcardExtension);
|
|
|
|
NTStatus = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
ExitSetSpeed:
|
|
|
|
*SmartcardExtension->IoRequest.Information = 0L;
|
|
if (NTStatus != STATUS_SUCCESS) {
|
|
NTStatus = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
SmartcardExtension->ReaderExtension->fTActive=FALSE;
|
|
CMMOB_SetFlags1(SmartcardExtension->ReaderExtension);
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!SetSpeed: Exit %lx\n",DRIVER_NAME,NTStatus));
|
|
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Routine Description:
|
|
This function always returns 'CardManMobile'.
|
|
|
|
|
|
Arguments: pointer to SMARTCARD_EXTENSION
|
|
|
|
|
|
|
|
Return Value: NT status
|
|
|
|
*****************************************************************************/
|
|
NTSTATUS CMMOB_ReadDeviceDescription(
|
|
IN PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
BYTE abDeviceDescription[] = "CardManMobile";
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!ReadDeviceDescription : Enter\n",DRIVER_NAME));
|
|
|
|
if (SmartcardExtension->IoRequest.ReplyBufferLength < sizeof(abDeviceDescription)) {
|
|
NTStatus = STATUS_BUFFER_OVERFLOW;
|
|
*SmartcardExtension->IoRequest.Information = 0L;
|
|
goto ExitReadDeviceDescription;
|
|
} else {
|
|
RtlCopyBytes((PVOID)SmartcardExtension->IoRequest.ReplyBuffer,
|
|
(PVOID)abDeviceDescription,sizeof(abDeviceDescription));
|
|
*SmartcardExtension->IoRequest.Information = sizeof(abDeviceDescription);
|
|
}
|
|
|
|
ExitReadDeviceDescription:
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!ReadDeviceDescription : Exit %lx\n",DRIVER_NAME,NTStatus));
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
Routine Description:
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
*****************************************************************************/
|
|
NTSTATUS CMMOB_GetFWVersion (
|
|
IN PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!GetFWVersion : Enter\n",DRIVER_NAME));
|
|
|
|
if (SmartcardExtension->IoRequest.ReplyBufferLength < sizeof (ULONG)) {
|
|
NTStatus = STATUS_BUFFER_OVERFLOW;
|
|
*SmartcardExtension->IoRequest.Information = 0;
|
|
} else {
|
|
*(PULONG)(SmartcardExtension->IoRequest.ReplyBuffer) =
|
|
SmartcardExtension->ReaderExtension->ulFWVersion;
|
|
*SmartcardExtension->IoRequest.Information = sizeof(ULONG);
|
|
}
|
|
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!GetFWVersion : Exit %lx\n",DRIVER_NAME,NTStatus));
|
|
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_CardTracking:
|
|
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
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_CardTracking(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
KIRQL CurrentIrql;
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!CardTracking: Enter\n",DRIVER_NAME ));
|
|
|
|
//
|
|
// set cancel routine
|
|
//
|
|
IoAcquireCancelSpinLock( &CurrentIrql );
|
|
IoSetCancelRoutine(SmartcardExtension->OsData->NotificationIrp,
|
|
CMMOB_CancelCardTracking);
|
|
IoReleaseCancelSpinLock( CurrentIrql );
|
|
|
|
//
|
|
// Mark notification irp pending
|
|
//
|
|
IoMarkIrpPending(SmartcardExtension->OsData->NotificationIrp);
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!CardTracking: Exit\n",DRIVER_NAME ));
|
|
|
|
return( STATUS_PENDING );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
CMMOB_CompleteCardTracking:
|
|
finishes a pending tracking request if the device will be unloaded
|
|
|
|
Arguments:
|
|
DeviceObject context of the request
|
|
NTStatus NTStatus to report to the calling process
|
|
|
|
Return Value:
|
|
|
|
******************************************************************************/
|
|
VOID CMMOB_CompleteCardTracking(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
KIRQL ioIrql, keIrql;
|
|
PIRP NotificationIrp;
|
|
|
|
IoAcquireCancelSpinLock(&ioIrql);
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&keIrql);
|
|
|
|
NotificationIrp = SmartcardExtension->OsData->NotificationIrp;
|
|
SmartcardExtension->OsData->NotificationIrp = NULL;
|
|
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
keIrql);
|
|
|
|
if (NotificationIrp!=NULL) {
|
|
IoSetCancelRoutine(NotificationIrp, NULL);
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(ioIrql);
|
|
|
|
if (NotificationIrp!=NULL) {
|
|
//finish the request
|
|
if (NotificationIrp->Cancel) {
|
|
NotificationIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
} else {
|
|
NotificationIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
}
|
|
NotificationIrp->IoStatus.Information = 0;
|
|
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
("%s!CompleteCardTracking: Completing Irp %lx Status=%lx\n",
|
|
DRIVER_NAME, NotificationIrp,NotificationIrp->IoStatus.Status));
|
|
|
|
IoCompleteRequest(NotificationIrp, IO_NO_INCREMENT );
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_CancelCardTracking
|
|
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
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_CancelCardTracking(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
|
|
PSMARTCARD_EXTENSION SmartcardExtension = &DeviceExtension->SmartcardExtension;
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!CancelCardTracking: Enter\n",DRIVER_NAME));
|
|
|
|
ASSERT(Irp == SmartcardExtension->OsData->NotificationIrp);
|
|
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
CMMOB_CompleteCardTracking(SmartcardExtension);
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!CancelCardTracking: Exit\n",DRIVER_NAME));
|
|
|
|
return STATUS_CANCELLED;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_StartCardTracking:
|
|
|
|
Arguments:
|
|
DeviceObject context of call
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
NTStatus returned by LowLevel routines
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_StartCardTracking(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
HANDLE hThread;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
PSMARTCARD_EXTENSION SmartcardExtension;
|
|
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
SmartcardExtension = &DeviceExtension->SmartcardExtension;
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
( "%s!StartCardTracking: Enter\n",DRIVER_NAME));
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
( "%s!StartCardTracking: IRQL %i\n",DRIVER_NAME,KeGetCurrentIrql()));
|
|
|
|
KeWaitForSingleObject(&SmartcardExtension->ReaderExtension->CardManIOMutex,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
// settings for thread synchronization
|
|
SmartcardExtension->ReaderExtension->fTerminateUpdateThread = FALSE;
|
|
|
|
// create thread for updating current state
|
|
NTStatus = PsCreateSystemThread(&hThread,
|
|
THREAD_ALL_ACCESS,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
CMMOB_UpdateCurrentStateThread,
|
|
DeviceObject);
|
|
|
|
if (NT_SUCCESS(NTStatus)) {
|
|
//
|
|
// We've got the thread. Now get a pointer to it.
|
|
//
|
|
NTStatus = ObReferenceObjectByHandle(hThread,
|
|
THREAD_ALL_ACCESS,
|
|
NULL,
|
|
KernelMode,
|
|
&SmartcardExtension->ReaderExtension->ThreadObjectPointer,
|
|
NULL);
|
|
|
|
if (NT_ERROR(NTStatus)) {
|
|
|
|
ZwClose(hThread);
|
|
SmartcardExtension->ReaderExtension->fTerminateUpdateThread = TRUE;
|
|
} else {
|
|
//
|
|
// Now that we have a reference to the thread
|
|
// we can simply close the handle.
|
|
//
|
|
ZwClose(hThread);
|
|
|
|
SmartcardExtension->ReaderExtension->fUpdateThreadRunning = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
("%s!-----------------------------------------------------------\n",DRIVER_NAME));
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
("%s!STARTING THREAD\n",DRIVER_NAME));
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
("%s!-----------------------------------------------------------\n",DRIVER_NAME));
|
|
|
|
KeReleaseMutex(&SmartcardExtension->ReaderExtension->CardManIOMutex,FALSE);
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
( "%s!CMMOB_StartCardTracking: Exit %lx\n",DRIVER_NAME,NTStatus));
|
|
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_StopCardTracking:
|
|
|
|
Arguments:
|
|
DeviceObject context of call
|
|
|
|
Return Value:
|
|
******************************************************************************/
|
|
VOID CMMOB_StopCardTracking(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
PSMARTCARD_EXTENSION SmartcardExtension;
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
( "%s!StopCardTracking: Enter\n",DRIVER_NAME));
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
( "%s!StopCardTracking: IRQL %i\n",DRIVER_NAME,KeGetCurrentIrql()));
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
SmartcardExtension = &DeviceExtension->SmartcardExtension;
|
|
|
|
if (SmartcardExtension->ReaderExtension->fUpdateThreadRunning) {
|
|
|
|
// kill thread
|
|
KeWaitForSingleObject(&SmartcardExtension->ReaderExtension->CardManIOMutex,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL );
|
|
|
|
SmartcardExtension->ReaderExtension->fTerminateUpdateThread = TRUE;
|
|
|
|
KeReleaseMutex(&SmartcardExtension->ReaderExtension->CardManIOMutex,FALSE);
|
|
|
|
|
|
//
|
|
// Wait on the thread handle, when the wait is satisfied, the
|
|
// thread has gone away.
|
|
//
|
|
KeWaitForSingleObject(SmartcardExtension->ReaderExtension->ThreadObjectPointer,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
}
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
( "%s!StopCardTracking: Exit\n",DRIVER_NAME));
|
|
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
CMMOB_UpdateCurrentStateThread:
|
|
|
|
Arguments:
|
|
DeviceObject context of call
|
|
|
|
Return Value:
|
|
******************************************************************************/
|
|
VOID CMMOB_UpdateCurrentStateThread(
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
PDEVICE_OBJECT DeviceObject = Context;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
PSMARTCARD_EXTENSION SmartcardExtension;
|
|
ULONG ulInterval;
|
|
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
SmartcardExtension = &DeviceExtension->SmartcardExtension;
|
|
|
|
KeWaitForSingleObject(&DeviceExtension->CanRunUpdateThread,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
( "%s!UpdateCurrentStateThread: started\n",DRIVER_NAME));
|
|
|
|
while (TRUE) {
|
|
// every 500 ms the NTStatus request is sent
|
|
ulInterval = 500;
|
|
KeWaitForSingleObject(&SmartcardExtension->ReaderExtension->CardManIOMutex,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (SmartcardExtension->ReaderExtension->fTerminateUpdateThread) {
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
("%s!-----------------------------------------------------------\n",DRIVER_NAME));
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
("%s!UpdateCurrentStateThread: STOPPING THREAD\n",DRIVER_NAME));
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
("%s!-----------------------------------------------------------\n",DRIVER_NAME));
|
|
|
|
KeReleaseMutex(&SmartcardExtension->ReaderExtension->CardManIOMutex,FALSE);
|
|
SmartcardExtension->ReaderExtension->fUpdateThreadRunning = FALSE;
|
|
PsTerminateSystemThread( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
//
|
|
// get current card state
|
|
//
|
|
NTStatus = CMMOB_UpdateCurrentState(SmartcardExtension);
|
|
if (NTStatus == STATUS_DEVICE_DATA_ERROR) {
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
("%s!UpdateCurrentStateThread: setting update interval to 1ms\n",DRIVER_NAME));
|
|
ulInterval = 1;
|
|
} else if (NTStatus != STATUS_SUCCESS &&
|
|
NTStatus != STATUS_NO_SUCH_DEVICE) {
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
("%s!UpdateCurrentStateThread: UpdateCurrentState failed!\n",DRIVER_NAME));
|
|
}
|
|
|
|
KeReleaseMutex(&SmartcardExtension->ReaderExtension->CardManIOMutex,FALSE);
|
|
|
|
SysDelay (ulInterval);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_UpdateCurrentState:
|
|
|
|
Arguments:
|
|
DeviceObject context of call
|
|
|
|
Return Value:
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_UpdateCurrentState(
|
|
IN PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
BOOL fCardStateChanged = FALSE;
|
|
KIRQL irql;
|
|
|
|
//
|
|
// get card state from cardman
|
|
//
|
|
NTStatus = CMMOB_ResetReader(SmartcardExtension->ReaderExtension);
|
|
if (NTStatus == STATUS_SUCCESS ||
|
|
NTStatus == STATUS_NO_SUCH_DEVICE) {
|
|
if (NTStatus == STATUS_SUCCESS) {
|
|
if (CMMOB_CardInserted(SmartcardExtension->ReaderExtension)) {
|
|
if (CMMOB_CardPowered(SmartcardExtension->ReaderExtension))
|
|
SmartcardExtension->ReaderExtension->ulNewCardState = POWERED;
|
|
else
|
|
SmartcardExtension->ReaderExtension->ulNewCardState = INSERTED;
|
|
} else
|
|
SmartcardExtension->ReaderExtension->ulNewCardState = REMOVED;
|
|
} else
|
|
SmartcardExtension->ReaderExtension->ulNewCardState = REMOVED;
|
|
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
&irql);
|
|
if (SmartcardExtension->ReaderExtension->ulNewCardState == INSERTED &&
|
|
SmartcardExtension->ReaderExtension->ulOldCardState == POWERED ) {
|
|
// card has been removed and reinserted
|
|
SmartcardExtension->ReaderExtension->ulNewCardState = REMOVED;
|
|
}
|
|
|
|
if ((SmartcardExtension->ReaderExtension->ulNewCardState == INSERTED &&
|
|
(SmartcardExtension->ReaderExtension->ulOldCardState == UNKNOWN ||
|
|
SmartcardExtension->ReaderExtension->ulOldCardState == REMOVED )) ||
|
|
(SmartcardExtension->ReaderExtension->ulNewCardState == POWERED &&
|
|
SmartcardExtension->ReaderExtension->ulOldCardState == UNKNOWN )) {
|
|
// card has been inserted
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
("%s!UpdateCurrentState: smartcard inserted\n",DRIVER_NAME));
|
|
SmartcardExtension->ReaderExtension->ulOldCardState = SmartcardExtension->ReaderExtension->ulNewCardState;
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SWALLOWED;
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
|
|
fCardStateChanged = TRUE;
|
|
}
|
|
|
|
if (SmartcardExtension->ReaderExtension->ulNewCardState == REMOVED &&
|
|
(SmartcardExtension->ReaderExtension->ulOldCardState == UNKNOWN ||
|
|
SmartcardExtension->ReaderExtension->ulOldCardState == INSERTED ||
|
|
SmartcardExtension->ReaderExtension->ulOldCardState == POWERED )) {
|
|
// card has been removed
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
("%s!UpdateCurrentState: smartcard removed\n",DRIVER_NAME));
|
|
SmartcardExtension->ReaderExtension->ulOldCardState = SmartcardExtension->ReaderExtension->ulNewCardState;
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_ABSENT;
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
|
|
fCardStateChanged = TRUE;
|
|
|
|
// clear any cardspecific data
|
|
SmartcardExtension->CardCapabilities.ATR.Length = 0;
|
|
RtlFillMemory((PVOID)&SmartcardExtension->ReaderExtension->CardParameters,
|
|
sizeof(CARD_PARAMETERS), 0x00);
|
|
}
|
|
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
|
|
irql);
|
|
// complete IOCTL_SMARTCARD_IS_ABSENT or IOCTL_SMARTCARD_IS_PRESENT
|
|
if (fCardStateChanged == TRUE &&
|
|
SmartcardExtension->OsData->NotificationIrp ) {
|
|
SmartcardDebug(DEBUG_DRIVER,("%s!UpdateCurrentState: completing IRP\n",DRIVER_NAME));
|
|
CMMOB_CompleteCardTracking(SmartcardExtension);
|
|
}
|
|
|
|
}
|
|
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_ResetReader:
|
|
Resets the reader
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
none
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_ResetReader(
|
|
PREADER_EXTENSION ReaderExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus;
|
|
BOOLEAN fToggle;
|
|
UCHAR bFlags1;
|
|
|
|
NTStatus = CMMOB_WriteRegister(ReaderExtension,ADDR_WRITEREG_FLAGS0,CMD_RESET_SM);
|
|
if (NTStatus != STATUS_SUCCESS)
|
|
return NTStatus;
|
|
|
|
|
|
// check for reader presence
|
|
bFlags1 = ReaderExtension->bPreviousFlags1;
|
|
bFlags1 |= FLAG_CHECK_PRESENCE;
|
|
NTStatus = CMMOB_WriteRegister(ReaderExtension, ADDR_WRITEREG_FLAGS1, bFlags1);
|
|
// don't check for status because
|
|
// we have to set back fCheckPresence for proper working
|
|
fToggle = CMMOB_GetReceiveFlag(ReaderExtension);
|
|
bFlags1 = ReaderExtension->bPreviousFlags1;
|
|
NTStatus = CMMOB_WriteRegister(ReaderExtension, ADDR_WRITEREG_FLAGS1, bFlags1);
|
|
if (NTStatus != STATUS_SUCCESS)
|
|
return NTStatus;
|
|
if (fToggle == CMMOB_GetReceiveFlag(ReaderExtension)) {
|
|
SmartcardDebug(DEBUG_DRIVER,
|
|
("%s!ResetReader: CardMan Mobile removed!\n",DRIVER_NAME));
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_BytesReceived:
|
|
Reads how many bytes are already received from the card by the reader
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
NTStatus
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_BytesReceived(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
PULONG pulBytesReceived
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
ULONG ulBytesReceived;
|
|
ULONG ulBytesReceivedCheck;
|
|
UCHAR bReg;
|
|
|
|
/*
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
( "%s!BytesReceived Enter\n",DRIVER_NAME));
|
|
*/
|
|
*pulBytesReceived=0;
|
|
if (CMMOB_GetReceiveFlag(ReaderExtension) ||
|
|
ReaderExtension->CardParameters.fT0Mode) {
|
|
do {
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_BYTES_RECEIVED,&bReg);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
return NTStatus;
|
|
ulBytesReceived=bReg;
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_FLAGS0,&bReg);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
return NTStatus;
|
|
if ((bReg & FLAG_BYTES_RECEIVED_B9) == FLAG_BYTES_RECEIVED_B9) {
|
|
ulBytesReceived+=0x100;
|
|
}
|
|
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_BYTES_RECEIVED,&bReg);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
return NTStatus;
|
|
ulBytesReceivedCheck=bReg;
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_FLAGS0,&bReg);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
return NTStatus;
|
|
if ((bReg & FLAG_BYTES_RECEIVED_B9) == FLAG_BYTES_RECEIVED_B9) {
|
|
ulBytesReceivedCheck+=0x100;
|
|
}
|
|
}
|
|
while (ulBytesReceived!=ulBytesReceivedCheck);
|
|
*pulBytesReceived=ulBytesReceived;
|
|
}
|
|
/*
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
( "%s!BytesReceived Exit\n",DRIVER_NAME));
|
|
*/
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_SetFlags1:
|
|
Sets register Flags1
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
none
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_SetFlags1 (
|
|
PREADER_EXTENSION ReaderExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR bFlags1;
|
|
|
|
bFlags1 = ReaderExtension->CardParameters.bBaudRateHigh;
|
|
if (ReaderExtension->CardParameters.fInversRevers)
|
|
bFlags1 |= FLAG_INVERS_PARITY;
|
|
if (ReaderExtension->CardParameters.bClockFrequency==8)
|
|
bFlags1 |= FLAG_CLOCK_8MHZ;
|
|
if (ReaderExtension->CardParameters.fT0Write)
|
|
bFlags1 |= FLAG_T0_WRITE;
|
|
|
|
if (ReaderExtension->bAddressHigh == 1)
|
|
bFlags1 |= FLAG_BUFFER_ADDR_B9;
|
|
if (ReaderExtension->fTActive)
|
|
bFlags1 |= FLAG_TACTIVE;
|
|
if (ReaderExtension->fReadCIS)
|
|
bFlags1 |= FLAG_READ_CIS;
|
|
|
|
ReaderExtension->bPreviousFlags1=bFlags1;
|
|
NTStatus = CMMOB_WriteRegister(ReaderExtension, ADDR_WRITEREG_FLAGS1, bFlags1);
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_SetCardParameters:
|
|
Sets card parameters (baudrate, stopbits)
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
none
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_SetCardParameters (
|
|
PREADER_EXTENSION ReaderExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
|
|
NTStatus = CMMOB_SetFlags1 (ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
return NTStatus;
|
|
|
|
NTStatus = CMMOB_WriteRegister(ReaderExtension, ADDR_WRITEREG_BAUDRATE,
|
|
ReaderExtension->CardParameters.bBaudRateLow);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
return NTStatus;
|
|
|
|
NTStatus = CMMOB_WriteRegister(ReaderExtension, ADDR_WRITEREG_STOPBITS,
|
|
ReaderExtension->CardParameters.bStopBits);
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_CardInserted:
|
|
Sets card parameters (baudrate, stopbits)
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
TRUE if card is inserted
|
|
******************************************************************************/
|
|
BOOLEAN CMMOB_CardInserted(
|
|
IN PREADER_EXTENSION ReaderExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus=STATUS_SUCCESS;
|
|
UCHAR bReg;
|
|
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_FLAGS0,&bReg);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
return FALSE;
|
|
/*
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!CardInserted: ReadReg Flags0 = %x\n",DRIVER_NAME, (ULONG)bReg));
|
|
*/
|
|
if ((bReg & FLAG_INSERTED)==FLAG_INSERTED) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
CMMOB_CardPowered:
|
|
Sets card parameters (baudrate, stopbits)
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
TRUE if card is powered
|
|
******************************************************************************/
|
|
BOOLEAN CMMOB_CardPowered(
|
|
IN PREADER_EXTENSION ReaderExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus=STATUS_SUCCESS;
|
|
UCHAR bReg;
|
|
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_FLAGS0,&bReg);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
return FALSE;
|
|
if ((bReg & FLAG_POWERED)==FLAG_POWERED) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_ProcedureReceived:
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
TRUE if a procedure byte has been received
|
|
******************************************************************************/
|
|
BOOLEAN CMMOB_ProcedureReceived(
|
|
IN PREADER_EXTENSION ReaderExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus=STATUS_SUCCESS;
|
|
UCHAR bReg;
|
|
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_FLAGS1,&bReg);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
return FALSE;
|
|
if ((bReg & FLAG_NOPROCEDURE_RECEIVED)!=FLAG_NOPROCEDURE_RECEIVED) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
CMMOB_GetReceiveFlag:
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
TRUE if a receive flag is set
|
|
******************************************************************************/
|
|
BOOLEAN CMMOB_GetReceiveFlag(
|
|
IN PREADER_EXTENSION ReaderExtension
|
|
)
|
|
{
|
|
NTSTATUS NTStatus=STATUS_SUCCESS;
|
|
UCHAR bReg;
|
|
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_FLAGS0,&bReg);
|
|
/*
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!GetReceiveFlag: ReadReg Flags0 = %x\n",DRIVER_NAME, (ULONG)bReg));
|
|
*/
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
return FALSE;
|
|
if ((bReg & FLAG_RECEIVE)==FLAG_RECEIVE) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
CMMOB_GetProcedureByte:
|
|
Reads how many bytes are already received from the card by the reader
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
NTStatus
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_GetProcedureByte(
|
|
IN PREADER_EXTENSION ReaderExtension,
|
|
OUT PUCHAR pbProcedureByte
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR bReg;
|
|
UCHAR bRegPrevious;
|
|
|
|
do {
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_LASTPROCEDURE_T0,&bRegPrevious);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
return NTStatus;
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_LASTPROCEDURE_T0,&bReg);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
return NTStatus;
|
|
}
|
|
while (bReg!=bRegPrevious);
|
|
*pbProcedureByte=bReg;
|
|
return NTStatus;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
CMMOB_WriteT0:
|
|
Writes T0 request to card
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
NT STATUS
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_WriteT0(
|
|
IN PREADER_EXTENSION ReaderExtension,
|
|
IN ULONG ulBytesToWrite,
|
|
IN ULONG ulBytesToReceive,
|
|
IN PUCHAR pbData
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR bFlags0;
|
|
UCHAR bReg;
|
|
|
|
if (ulBytesToWrite > CMMOB_MAXBUFFER) {
|
|
NTStatus = STATUS_BUFFER_OVERFLOW;
|
|
return NTStatus;
|
|
}
|
|
// dummy read, to reset flag procedure received
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_FLAGS1,&bReg);
|
|
|
|
NTStatus = CMMOB_WriteBuffer(ReaderExtension,ulBytesToWrite,pbData);
|
|
if (NTStatus != STATUS_SUCCESS)
|
|
return NTStatus;
|
|
|
|
// write instruction byte to register
|
|
NTStatus = CMMOB_WriteRegister(ReaderExtension,ADDR_WRITEREG_PROCEDURE_T0,pbData[1]);
|
|
if (NTStatus != STATUS_SUCCESS)
|
|
return NTStatus;
|
|
|
|
// write message length
|
|
NTStatus = CMMOB_WriteRegister(ReaderExtension,ADDR_WRITEREG_MESSAGE_LENGTH,
|
|
(UCHAR)((ulBytesToWrite+ulBytesToReceive) & 0xFF));
|
|
if (NTStatus != STATUS_SUCCESS)
|
|
return NTStatus;
|
|
if ((ulBytesToWrite+ulBytesToReceive) > 0xFF) {
|
|
bFlags0=1;
|
|
} else {
|
|
bFlags0=0;
|
|
}
|
|
bFlags0 |= CMD_WRITE_T0;
|
|
NTStatus = CMMOB_WriteRegister(ReaderExtension,ADDR_WRITEREG_FLAGS0,bFlags0);
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_WriteT1:
|
|
Writes T1 request to card
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
NT STATUS
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_WriteT1(
|
|
IN PREADER_EXTENSION ReaderExtension,
|
|
IN ULONG ulBytesToWrite,
|
|
IN PUCHAR pbData
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR bFlags0;
|
|
|
|
if (ulBytesToWrite > CMMOB_MAXBUFFER) {
|
|
NTStatus = STATUS_BUFFER_OVERFLOW;
|
|
return NTStatus;
|
|
}
|
|
NTStatus = CMMOB_WriteBuffer(ReaderExtension,ulBytesToWrite,pbData);
|
|
if (NTStatus != STATUS_SUCCESS)
|
|
return NTStatus;
|
|
NTStatus = CMMOB_WriteRegister(ReaderExtension,ADDR_WRITEREG_MESSAGE_LENGTH,
|
|
(UCHAR)(ulBytesToWrite & 0xFF));
|
|
if (NTStatus != STATUS_SUCCESS)
|
|
return NTStatus;
|
|
if (ulBytesToWrite > 0xFF) {
|
|
bFlags0=1;
|
|
} else {
|
|
bFlags0=0;
|
|
}
|
|
bFlags0 |= CMD_WRITE_T1;
|
|
NTStatus = CMMOB_WriteRegister(ReaderExtension,ADDR_WRITEREG_FLAGS0,bFlags0);
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_ReadT0:
|
|
Reads T0 reply from card
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
NT STATUS
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_ReadT0(
|
|
IN PREADER_EXTENSION ReaderExtension,
|
|
IN ULONG ulBytesToRead,
|
|
IN ULONG ulBytesSent,
|
|
IN ULONG ulCWT,
|
|
OUT PUCHAR pbData,
|
|
OUT PULONG pulBytesRead,
|
|
OUT PBOOLEAN pfDataSent
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
KTIMER TimerWait;
|
|
ULONG ulBytesReceived;
|
|
ULONG ulBytesReceivedPrevious;
|
|
LARGE_INTEGER liWaitTime;
|
|
BOOLEAN fTimeExpired;
|
|
BOOLEAN fProcedureReceived;
|
|
BOOLEAN fTransmissionFinished;
|
|
UCHAR bProcedureByte=0;
|
|
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!ReadT0: Enter BytesToRead = %li\n",DRIVER_NAME,ulBytesToRead));
|
|
|
|
//initialize Timer
|
|
KeInitializeTimer(&TimerWait);
|
|
liWaitTime = RtlConvertLongToLargeInteger(ulCWT * -10000L);
|
|
|
|
*pulBytesRead = 0;
|
|
*pfDataSent = FALSE;
|
|
|
|
do {
|
|
KeSetTimer(&TimerWait,liWaitTime,NULL);
|
|
NTStatus=CMMOB_BytesReceived (ReaderExtension,&ulBytesReceivedPrevious);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitReadT0;
|
|
do {
|
|
fTimeExpired = KeReadStateTimer(&TimerWait);
|
|
fTransmissionFinished=CMMOB_GetReceiveFlag(ReaderExtension);
|
|
fProcedureReceived=CMMOB_ProcedureReceived(ReaderExtension);
|
|
NTStatus=CMMOB_BytesReceived (ReaderExtension,&ulBytesReceived);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitReadT0;
|
|
// wait 1 ms, so that processor is not blocked
|
|
SysDelay(1);
|
|
}
|
|
while (fTimeExpired==FALSE &&
|
|
fProcedureReceived==FALSE &&
|
|
ulBytesReceivedPrevious == ulBytesReceived &&
|
|
fTransmissionFinished==FALSE);
|
|
|
|
if (fProcedureReceived) {
|
|
NTStatus=CMMOB_GetProcedureByte (ReaderExtension,&bProcedureByte);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitReadT0;
|
|
// check for SW1
|
|
if (ReaderExtension->CardParameters.fInversRevers) {
|
|
CMMOB_InverseBuffer(&bProcedureByte,1);
|
|
}
|
|
}
|
|
|
|
if (!fTimeExpired) {
|
|
KeCancelTimer(&TimerWait);
|
|
}
|
|
#ifdef DBG
|
|
else {
|
|
SmartcardDebug(DEBUG_PROTOCOL,( "%s!----------------------------------------------\n",DRIVER_NAME));
|
|
SmartcardDebug(DEBUG_PROTOCOL,( "%s!Read T0 timed out\n",DRIVER_NAME));
|
|
SmartcardDebug(DEBUG_PROTOCOL,( "%s!----------------------------------------------\n",DRIVER_NAME));
|
|
}
|
|
#endif
|
|
|
|
}
|
|
while (fTimeExpired==FALSE &&
|
|
fTransmissionFinished==FALSE);
|
|
|
|
// read once more ulBytesReceived
|
|
// this value could have changed in the meantime
|
|
NTStatus=CMMOB_BytesReceived (ReaderExtension,&ulBytesReceived);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitReadT0;
|
|
|
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|
("%s!ReadT0: BytesReceived = %li\n",DRIVER_NAME,ulBytesReceived));
|
|
|
|
//now we should have received a reply
|
|
NTStatus=CMMOB_ResetReader (ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitReadT0;
|
|
|
|
// check for valid SW1
|
|
if ((bProcedureByte > 0x60 && bProcedureByte <= 0x6F) ||
|
|
(bProcedureByte >= 0x90 && bProcedureByte <= 0x9F)) {
|
|
if (ReaderExtension->CardParameters.fInversRevers) {
|
|
CMMOB_InverseBuffer(&bProcedureByte,1);
|
|
}
|
|
if (ulBytesReceived > ulBytesSent) {
|
|
|
|
if (ulBytesReceived - ulBytesSent > MIN_BUFFER_SIZE) {
|
|
NTStatus = STATUS_BUFFER_OVERFLOW;
|
|
goto ExitReadT0;
|
|
}
|
|
NTStatus=CMMOB_ReadBuffer(ReaderExtension, ulBytesSent,
|
|
ulBytesReceived-ulBytesSent, pbData);
|
|
if (NTStatus==STATUS_SUCCESS) {
|
|
// we have to insert the procedure byte (SW1)
|
|
pbData[ulBytesReceived-ulBytesSent]=pbData[ulBytesReceived-ulBytesSent-1];
|
|
pbData[ulBytesReceived-ulBytesSent-1]=bProcedureByte;
|
|
*pulBytesRead=ulBytesReceived-ulBytesSent+1;
|
|
}
|
|
|
|
if (ulBytesSent > T0_HEADER_LEN) {
|
|
*pfDataSent = TRUE;
|
|
}
|
|
} else {
|
|
if (ulBytesReceived > T0_HEADER_LEN) {
|
|
// it seems not all bytes were accepted by the card
|
|
// but we got SW1 SW2 - return only SW1 SW2
|
|
pbData[0]=bProcedureByte;
|
|
NTStatus=CMMOB_ReadBuffer(ReaderExtension, ulBytesReceived-1,
|
|
1, &pbData[1]);
|
|
*pulBytesRead=2;
|
|
} else {
|
|
NTStatus = STATUS_IO_TIMEOUT;
|
|
}
|
|
}
|
|
} else {
|
|
NTStatus = STATUS_IO_TIMEOUT;
|
|
}
|
|
|
|
ExitReadT0:
|
|
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!ReadT0: Exit\n",DRIVER_NAME ));
|
|
|
|
return NTStatus;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
CMMOB_ReadT1:
|
|
Reads T1 reply from card
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
NT STATUS
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_ReadT1(
|
|
IN PREADER_EXTENSION ReaderExtension,
|
|
IN LONG lBytesToRead,
|
|
IN ULONG ulBWT,
|
|
IN ULONG ulCWT,
|
|
OUT PUCHAR pbData,
|
|
OUT PULONG pulBytesRead
|
|
)
|
|
// a negative value of ulBytesToRead indicates a relative number of bytes to read
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
KTIMER TimerWait;
|
|
ULONG ulBytesReceived;
|
|
LARGE_INTEGER liWaitTime;
|
|
BOOLEAN fTimeExpired;
|
|
ULONG ulBytesReceivedPrevious;
|
|
|
|
/*
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!ReadT1: Enter\n",DRIVER_NAME ));
|
|
*/
|
|
|
|
//initialize Timer
|
|
KeInitializeTimer(&TimerWait);
|
|
|
|
*pulBytesRead = 0;
|
|
// first wait BWT (block waiting time)
|
|
liWaitTime = RtlConvertLongToLargeInteger(ulBWT * -10000L);
|
|
do {
|
|
KeSetTimer(&TimerWait,liWaitTime,NULL);
|
|
NTStatus=CMMOB_BytesReceived (ReaderExtension,&ulBytesReceivedPrevious);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitReadT1;
|
|
do {
|
|
fTimeExpired = KeReadStateTimer(&TimerWait);
|
|
NTStatus=CMMOB_BytesReceived (ReaderExtension,&ulBytesReceived);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitReadT1;
|
|
// wait 1 ms, so that processor is not blocked
|
|
SysDelay(1);
|
|
|
|
// make an adjustment of lBytesToRead (only one time)
|
|
if (lBytesToRead<= 0 && ulBytesReceived >= 3) {
|
|
// get number of bytes to receive from reader
|
|
UCHAR bReg;
|
|
UCHAR bRegPrevious;
|
|
lBytesToRead = -lBytesToRead;
|
|
do {
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_BYTESTORECEIVE_T1,&bRegPrevious);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitReadT1;
|
|
NTStatus=CMMOB_ReadRegister(ReaderExtension,ADDR_READREG_BYTESTORECEIVE_T1,&bReg);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitReadT1;
|
|
}
|
|
while (bReg!=bRegPrevious);
|
|
lBytesToRead += bReg;
|
|
}
|
|
}
|
|
while (fTimeExpired==FALSE &&
|
|
ulBytesReceivedPrevious == ulBytesReceived &&
|
|
(lBytesToRead<=0 || ulBytesReceived!=(ULONG)lBytesToRead));
|
|
|
|
if (!fTimeExpired) {
|
|
KeCancelTimer(&TimerWait);
|
|
liWaitTime = RtlConvertLongToLargeInteger(ulCWT * -10000L);
|
|
// now wait only CWT (character waiting time)
|
|
}
|
|
#ifdef DBG
|
|
else {
|
|
SmartcardDebug(DEBUG_PROTOCOL,( "%s!----------------------------------------------\n",DRIVER_NAME));
|
|
SmartcardDebug(DEBUG_PROTOCOL,( "%s!Read T1 timed out\n",DRIVER_NAME));
|
|
SmartcardDebug(DEBUG_PROTOCOL,( "%s!----------------------------------------------\n",DRIVER_NAME));
|
|
}
|
|
#endif
|
|
}
|
|
while (!fTimeExpired &&
|
|
(lBytesToRead<=0 || ulBytesReceived!=(ULONG)lBytesToRead));
|
|
|
|
|
|
|
|
//now we should have received a reply
|
|
NTStatus=CMMOB_ResetReader (ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS)
|
|
goto ExitReadT1;
|
|
|
|
if (ulBytesReceived > CMMOB_MAXBUFFER) {
|
|
|
|
NTStatus = STATUS_BUFFER_OVERFLOW;
|
|
|
|
}
|
|
if (ulBytesReceived==(ULONG)lBytesToRead && lBytesToRead > 0) {
|
|
NTStatus=CMMOB_ReadBuffer(ReaderExtension, 0, (ULONG)lBytesToRead, pbData);
|
|
if (NTStatus==STATUS_SUCCESS) {
|
|
*pulBytesRead=(ULONG)lBytesToRead;
|
|
}
|
|
} else {
|
|
NTStatus=CMMOB_ReadBuffer(ReaderExtension, 0, ulBytesReceived, pbData);
|
|
if (NTStatus==STATUS_SUCCESS) {
|
|
*pulBytesRead=ulBytesReceived;
|
|
}
|
|
NTStatus = STATUS_IO_TIMEOUT;
|
|
}
|
|
|
|
ExitReadT1:
|
|
|
|
/*
|
|
SmartcardDebug(DEBUG_TRACE,
|
|
("%s!ReadT1: Exit\n",DRIVER_NAME ));
|
|
*/
|
|
return NTStatus;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
CMMOB_ReadRegister:
|
|
Sets card parameters (baudrate, stopbits)
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
NT STATUS
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_ReadRegister(
|
|
IN PREADER_EXTENSION ReaderExtension,
|
|
IN USHORT usAddress,
|
|
OUT PUCHAR pbData
|
|
)
|
|
{
|
|
*pbData = READ_PORT_UCHAR(ReaderExtension->pbRegsBase+usAddress);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_WriteRegister:
|
|
Sets card parameters (baudrate, stopbits)
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
NT STATUS
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_WriteRegister(
|
|
IN PREADER_EXTENSION ReaderExtension,
|
|
IN USHORT usAddress,
|
|
IN UCHAR bData
|
|
)
|
|
{
|
|
|
|
WRITE_PORT_UCHAR(ReaderExtension->pbRegsBase+usAddress,bData);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_ReadBuffer:
|
|
Sets card parameters (baudrate, stopbits)
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
NT STATUS
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_ReadBuffer(
|
|
IN PREADER_EXTENSION ReaderExtension,
|
|
IN ULONG ulOffset,
|
|
IN ULONG ulLength,
|
|
OUT PUCHAR pbData
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
ULONG i;
|
|
|
|
|
|
if ((ulOffset & 0x100) == 0x100) {
|
|
ReaderExtension->bAddressHigh=1;
|
|
} else {
|
|
ReaderExtension->bAddressHigh=0;
|
|
}
|
|
NTStatus = CMMOB_SetFlags1(ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS) {
|
|
goto ExitReadBuffer;
|
|
}
|
|
|
|
|
|
for (i=0; i<ulLength; i++) {
|
|
WRITE_PORT_UCHAR(ReaderExtension->pbRegsBase+ADDR_WRITEREG_BUFFER_ADDR,
|
|
(BYTE)((ulOffset+i)&0xFF));
|
|
// because we are counting up in a loop we have to set
|
|
// bit 9 of address only once
|
|
if (ulOffset+i == 0x100) {
|
|
ReaderExtension->bAddressHigh=1;
|
|
NTStatus = CMMOB_SetFlags1(ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS) {
|
|
goto ExitReadBuffer;
|
|
}
|
|
}
|
|
*(pbData+i)=READ_PORT_UCHAR(ReaderExtension->pbRegsBase+ADDR_WRITEREG_BUFFER_DATA);
|
|
// erase buffer - required for certification
|
|
WRITE_PORT_UCHAR(ReaderExtension->pbRegsBase+ADDR_WRITEREG_BUFFER_DATA,0);
|
|
|
|
}
|
|
ExitReadBuffer:
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
CMMOB_WriteBuffer:
|
|
Sets card parameters (baudrate, stopbits)
|
|
|
|
Arguments:
|
|
ReaderExtension context of the call
|
|
|
|
Return Value:
|
|
NT STATUS
|
|
******************************************************************************/
|
|
NTSTATUS CMMOB_WriteBuffer(
|
|
IN PREADER_EXTENSION ReaderExtension,
|
|
IN ULONG ulLength,
|
|
IN PUCHAR pbData
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
ULONG i;
|
|
|
|
|
|
ReaderExtension->bAddressHigh=0;
|
|
NTStatus = CMMOB_SetFlags1(ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS) {
|
|
goto ExitWriteBuffer;
|
|
}
|
|
|
|
for (i=0; i<ulLength; i++) {
|
|
WRITE_PORT_UCHAR(ReaderExtension->pbRegsBase+ADDR_WRITEREG_BUFFER_ADDR,
|
|
(BYTE)(i & 0xFF));
|
|
// because we are counting up in a loop we have to set
|
|
// bit 9 of address only once
|
|
if (i == 0x100) {
|
|
ReaderExtension->bAddressHigh=1;
|
|
NTStatus = CMMOB_SetFlags1(ReaderExtension);
|
|
if (NTStatus!=STATUS_SUCCESS) {
|
|
goto ExitWriteBuffer;
|
|
}
|
|
}
|
|
WRITE_PORT_UCHAR(ReaderExtension->pbRegsBase+ADDR_WRITEREG_BUFFER_DATA,*(pbData+i));
|
|
|
|
}
|
|
|
|
ExitWriteBuffer:
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Routine Description:
|
|
This routine inverts the buffer
|
|
Bit0 -> Bit 7
|
|
Bit1 -> Bit 6
|
|
Bit2 -> Bit 5
|
|
Bit3 -> Bit 4
|
|
Bit4 -> Bit 3
|
|
Bit5 -> Bit 2
|
|
Bit6 -> Bit 1
|
|
Bit7 -> Bit 0
|
|
|
|
|
|
Arguments: pbBuffer ... pointer to buffer
|
|
ulBufferSize ... size of buffer
|
|
|
|
|
|
Return Value: none
|
|
|
|
*****************************************************************************/
|
|
VOID CMMOB_InverseBuffer (
|
|
PUCHAR pbBuffer,
|
|
ULONG ulBufferSize
|
|
)
|
|
{
|
|
ULONG i,j;
|
|
UCHAR bRevers;
|
|
UCHAR bTemp;
|
|
|
|
for (i=0; i<ulBufferSize; i++) {
|
|
bRevers = 0;
|
|
for (j=0; j<8; j++) {
|
|
bTemp = pbBuffer[i] << j;
|
|
bTemp &= 0x80;
|
|
bRevers |= bTemp >> (7-j);
|
|
}
|
|
pbBuffer[i] = ~bRevers;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* History:
|
|
* $Log: cmbp0scr.c $
|
|
* Revision 1.7 2001/01/22 07:12:36 WFrischauf
|
|
* No comment given
|
|
*
|
|
* Revision 1.6 2000/09/25 14:24:31 WFrischauf
|
|
* No comment given
|
|
*
|
|
* Revision 1.5 2000/08/24 09:05:13 TBruendl
|
|
* No comment given
|
|
*
|
|
* Revision 1.4 2000/08/09 12:45:57 WFrischauf
|
|
* No comment given
|
|
*
|
|
* Revision 1.3 2000/07/27 13:53:03 WFrischauf
|
|
* No comment given
|
|
*
|
|
*
|
|
******************************************************************************/
|
|
|