/***************************************************************************** @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 #include #include // 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;iMinorIoControlCode])); 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; ipbRegsBase+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; ipbRegsBase+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> (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 * * ******************************************************************************/