/*++ Copyright (c) 1997 SCM Microsystems, Inc. Module Name: StcCmd.c Abstract: Basic command functions for STC smartcard reader Environment: Revision History: PP 01.19.1999 1.01 Modification for PC/SC YL 1.00 Initial Version --*/ #include "common.h" #include "StcCmd.h" #include "usbcom.h" #include "stcusbnt.h" const STC_REGISTER STCInitialize[] = { { ADR_SC_CONTROL, 0x01, 0x00 }, // reset { ADR_CLOCK_CONTROL, 0x01, 0x01 }, { ADR_CLOCK_CONTROL, 0x01, 0x03 }, { ADR_UART_CONTROL, 0x01, 0x27 }, { ADR_UART_CONTROL, 0x01, 0x4F }, { ADR_IO_CONFIG, 0x01, 0x02 }, // 0x10 eva board { ADR_FIFO_CONFIG, 0x01, 0x81 }, { ADR_INT_CONTROL, 0x01, 0x11 }, { 0x0E, 0x01, 0xC0 }, { 0x00, 0x00, 0x00 }, }; const STC_REGISTER STCClose[] = { { ADR_INT_CONTROL, 0x01, 0x00 }, { ADR_SC_CONTROL, 0x01, 0x00 }, // reset { ADR_UART_CONTROL, 0x01, 0x40 }, { ADR_CLOCK_CONTROL, 0x01, 0x01 }, { ADR_CLOCK_CONTROL, 0x01, 0x00 }, { 0x00, 0x00, 0x00 }, }; NTSTATUS STCResetInterface( PREADER_EXTENSION ReaderExtension) /*++ Description: Arguments: ReaderExtension context of call Return Value: --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; DWORD dwETU; dwETU = 0x7401 | 0x0080; NtStatus=IFWriteSTCRegister( ReaderExtension, ADR_ETULENGTH15, 2, (UCHAR *)&dwETU); return(NtStatus); } NTSTATUS STCReset( PREADER_EXTENSION ReaderExtension, UCHAR Device, BOOLEAN WarmReset, PUCHAR pATR, PULONG pATRLength) /*++ Description: performs a reset of ICC Arguments: ReaderExtension context of call Device device requested WarmReset kind of ICC reset pATR ptr to ATR buffer, NULL if no ATR required pATRLength size of ATR buffer / length of ATR Return Value: STATUS_SUCCESS STATUS_NO_MEDIA STATUS_UNRECOGNIZED_MEDIA error values from IFRead / IFWrite --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; // set UART to autolearn mode NTStatus = STCInitUART( ReaderExtension, TRUE ); if( NTStatus == STATUS_SUCCESS) { // // set default frequency for ATR // NTStatus = STCSetFDIV( ReaderExtension, FREQ_DIV ); if( NTStatus == STATUS_SUCCESS && ( !WarmReset )) { // // deactivate contacts // NTStatus = STCPowerOff( ReaderExtension ); } // // set power to card // if( NTStatus == STATUS_SUCCESS) { NTStatus = STCPowerOn( ReaderExtension ); if( NTStatus == STATUS_SUCCESS) { NTStatus = STCReadATR( ReaderExtension, pATR, pATRLength ); } } } if( NTStatus != STATUS_SUCCESS ) { STCPowerOff( ReaderExtension ); } return( NTStatus ); } NTSTATUS STCReadATR( PREADER_EXTENSION ReaderExtension, PUCHAR pATR, PULONG pATRLen) /*++ Description: Read and analize the ATR Arguments: ReaderExtension context of call pATR ptr to ATR buffer, pATRLen size of ATR buffer / length of ATR Return Value: --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR T0_Yx, T0_K, // number of historical bytes Protocol; ULONG ATRLen; // // set read timeout for ATR // ReaderExtension->ReadTimeout = 250; // only 250ms for this firs ATR // // read TS if active low reset // NTStatus = IFReadSTCData( ReaderExtension, pATR, 1 ); if( NTStatus == STATUS_IO_TIMEOUT ) { ReaderExtension->ReadTimeout = 2500; NTStatus = STCSetRST( ReaderExtension, TRUE ); if( NTStatus == STATUS_SUCCESS ) { NTStatus = IFReadSTCData( ReaderExtension, pATR, 1 ); } } Protocol = PROTOCOL_TO; ATRLen = 1; if( NTStatus == STATUS_SUCCESS ) { // T0 NTStatus = IFReadSTCData( ReaderExtension, pATR + ATRLen, 1 ); ATRLen++; /* Convention management */ if ( pATR[0] == 0x03 ) /* Direct convention */ { pATR[0] = 0x3F; } if ( ( pATR[0] != 0x3F ) && ( pATR[0] != 0x3B ) ) { NTStatus = STATUS_DATA_ERROR; } if( NTStatus == STATUS_SUCCESS ) { ULONG Request; // number of historical bytes T0_K = (UCHAR) ( pATR[ATRLen-1] & 0x0F ); // coding of TA, TB, TC, TD T0_Yx = (UCHAR) ( pATR[ATRLen-1] & 0xF0 ) >> 4; while(( NTStatus == STATUS_SUCCESS ) && T0_Yx ) { UCHAR Mask; // evaluate presence of TA, TB, TC, TD Mask = T0_Yx; Request = 0; while( Mask ) { if( Mask & 1 ) { Request++; } Mask >>= 1; } NTStatus = IFReadSTCData( ReaderExtension, pATR + ATRLen, Request ); ATRLen += Request; if (ATRLen >= ATR_SIZE) { NTStatus = STATUS_UNRECOGNIZED_MEDIA; break; } if( T0_Yx & TDx ) { // high nibble of TD codes the next set of TA, TB, TC, TD T0_Yx = ( pATR[ATRLen-1] & 0xF0 ) >> 4; // low nibble of TD codes the protocol Protocol = pATR[ATRLen-1] & 0x0F; } else { break; } } if( NTStatus == STATUS_SUCCESS ) { // historical bytes NTStatus = IFReadSTCData( ReaderExtension, pATR + ATRLen, T0_K ); // check sum if( NTStatus == STATUS_SUCCESS ) { ATRLen += T0_K; if( (ATRLen < ATR_SIZE) && (Protocol >= PROTOCOL_T1) ) { NTStatus = IFReadSTCData( ReaderExtension, pATR + ATRLen, 1 ); if( NTStatus == STATUS_SUCCESS ) { ATRLen++; } else if( NTStatus == STATUS_IO_TIMEOUT ) { // some cards don't support the TCK NTStatus = STATUS_SUCCESS; } } else { if (ATRLen >= ATR_SIZE) { NTStatus = STATUS_UNRECOGNIZED_MEDIA; } } } } } } if( NTStatus == STATUS_IO_TIMEOUT ) { NTStatus = STATUS_UNRECOGNIZED_MEDIA; } if(( NTStatus == STATUS_SUCCESS ) && ( pATRLen != NULL )) { *pATRLen = ATRLen; } return( NTStatus ); } NTSTATUS STCPowerOff( PREADER_EXTENSION ReaderExtension ) /*++ Description: Deactivates the requested device Arguments: ReaderExtension context of call Return Value: STATUS_SUCCESS error values from IFRead / IFWrite --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR SCCtrl; // clear SIM SCCtrl=0x11; NTStatus=IFWriteSTCRegister( ReaderExtension, ADR_INT_CONTROL, 1, &SCCtrl); SCCtrl = 0x00; NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_SC_CONTROL, 1, &SCCtrl ); return( NTStatus ); } NTSTATUS STCPowerOn( PREADER_EXTENSION ReaderExtension ) /*++ Description: Deactivates the requested device Arguments: ReaderExtension context of call Return Value: STATUS_SUCCESS error values from IFRead / IFWrite --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR SCCtrl,Byte; Byte = 0x02; NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_IO_CONFIG, 1, &Byte ); SCCtrl = 0x40; // vcc NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_SC_CONTROL, 1, &SCCtrl ); if( NTStatus == STATUS_SUCCESS ) { SCCtrl = 0x41; // vpp NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_SC_CONTROL, 1, &SCCtrl ); // set SIM SCCtrl = 0x13; NTStatus=IFWriteSTCRegister( ReaderExtension, ADR_INT_CONTROL, 1, &SCCtrl); if( NTStatus == STATUS_SUCCESS ) { SCCtrl = 0xD1; // vcc, clk, io NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_SC_CONTROL, 1, &SCCtrl ); } } return( NTStatus ); } NTSTATUS STCSetRST( PREADER_EXTENSION ReaderExtension, BOOLEAN On) /*++ Description: Arguments: ReaderExtension context of call Return Value: STATUS_SUCCESS error values from IFRead / IFWrite --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR SCCtrl = 0; NTStatus = IFReadSTCRegister( ReaderExtension, ADR_SC_CONTROL, 1,&SCCtrl ); if( NTStatus == STATUS_SUCCESS ) { if( On ) { SCCtrl |= 0x20; } else { SCCtrl &= ~0x20; } NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_SC_CONTROL, 1, &SCCtrl ); } return(NTStatus); } NTSTATUS STCConfigureSTC( PREADER_EXTENSION ReaderExtension, PSTC_REGISTER pConfiguration ) { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR Value; do { if( pConfiguration->Register == ADR_INT_CONTROL ) { // Read interrupt status register to acknoledge wrong states NTStatus = IFReadSTCRegister( ReaderExtension, ADR_INT_STATUS, 1, &Value ); } Value = (UCHAR) pConfiguration->Value; NTStatus = IFWriteSTCRegister( ReaderExtension, pConfiguration->Register, pConfiguration->Size, (PUCHAR)&pConfiguration->Value ); if (NTStatus == STATUS_NO_MEDIA) { // ignore that no card is in the reader NTStatus = STATUS_SUCCESS; } // delay to stabilize the oscilator clock: if( pConfiguration->Register == ADR_CLOCK_CONTROL ) { SysDelay( 100 ); } pConfiguration++; } while(NTStatus == STATUS_SUCCESS && pConfiguration->Size); return NTStatus; } NTSTATUS STCSetETU( PREADER_EXTENSION ReaderExtension, ULONG NewETU) /*++ Description: Arguments: ReaderExtension context of call Return Value: STATUS_SUCCESS error values from IFRead / IFWrite --*/ { NTSTATUS NTStatus = STATUS_DATA_ERROR; UCHAR ETU[2]; SmartcardDebug( DEBUG_TRACE, ("%s!STCSetETU %d\n", DRIVER_NAME, NewETU)); if( NewETU < 0x0FFF ) { NTStatus = IFReadSTCRegister( ReaderExtension, ADR_ETULENGTH15, 2, ETU); if( NTStatus == STATUS_SUCCESS ) { // // save all RFU bits // ETU[1] = (UCHAR) NewETU; ETU[0] = (UCHAR)(( ETU[0] & 0xF0 ) | ( NewETU >> 8 )); NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_ETULENGTH15, 2, ETU); } } return(NTStatus); } NTSTATUS STCSetCGT( PREADER_EXTENSION ReaderExtension, ULONG NewCGT) /*++ Description: Arguments: ReaderExtension context of call Return Value: STATUS_SUCCESS error values from IFRead / IFWrite --*/ { NTSTATUS NTStatus = STATUS_DATA_ERROR; UCHAR CGT[2]; SmartcardDebug( DEBUG_TRACE, ("%s!STCSetCGT %d\n", DRIVER_NAME, NewCGT)); if( NewCGT < 0x01FF ) { NTStatus = IFReadSTCRegister( ReaderExtension, ADR_CGT8, 2, CGT); if( NTStatus == STATUS_SUCCESS ) { // // save all RFU bits // CGT[1] = ( UCHAR )NewCGT; CGT[0] = (UCHAR)(( CGT[0] & 0xFE ) | ( NewCGT >> 8 )); NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_CGT8, 2, CGT); } } return(NTStatus); } NTSTATUS STCSetCWT( PREADER_EXTENSION ReaderExtension, ULONG NewCWT) /*++ Description: Arguments: ReaderExtension context of call Return Value: STATUS_SUCCESS error values from IFRead / IFWrite --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR CWT[4]; SmartcardDebug( DEBUG_TRACE, ("%s!STCSetCWT %d\n", DRIVER_NAME, NewCWT)); // little indians... CWT[0] = (( PUCHAR )&NewCWT )[3]; CWT[1] = (( PUCHAR )&NewCWT )[2]; CWT[2] = (( PUCHAR )&NewCWT )[1]; CWT[3] = (( PUCHAR )&NewCWT )[0]; NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_CWT31, 4, CWT ); return(NTStatus); } NTSTATUS STCSetBWT( PREADER_EXTENSION ReaderExtension, ULONG NewBWT) /*++ Description: Arguments: ReaderExtension context of call Return Value: STATUS_SUCCESS error values from IFRead / IFWrite --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR BWT[4]; SmartcardDebug( DEBUG_TRACE, ("%s!STCSetBWT %d\n", DRIVER_NAME, NewBWT)); // little indians... BWT[0] = (( PUCHAR )&NewBWT )[3]; BWT[1] = (( PUCHAR )&NewBWT )[2]; BWT[2] = (( PUCHAR )&NewBWT )[1]; BWT[3] = (( PUCHAR )&NewBWT )[0]; NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_BWT31, 4, BWT ); return(NTStatus); } NTSTATUS STCSetFDIV( PREADER_EXTENSION ReaderExtension, ULONG Factor) /*++ Description: Arguments: ReaderExtension context of call Return Value: STATUS_SUCCESS error values from IFRead / IFWrite --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR DIV = 0; NTStatus = IFReadSTCRegister( ReaderExtension, ADR_ETULENGTH15, 1, &DIV ); if( NTStatus == STATUS_SUCCESS ) { switch( Factor ) { case 1: DIV &= ~M_DIV0; DIV &= ~M_DIV1; break; case 2: DIV |= M_DIV0; DIV &= ~M_DIV1; break; case 4 : DIV &= ~M_DIV0; DIV |= M_DIV1; break; case 8 : DIV |= M_DIV0; DIV |= M_DIV1; break; default : NTStatus = STATUS_DATA_ERROR; } if( NTStatus == STATUS_SUCCESS ) { NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_ETULENGTH15, 1, &DIV ); } } return(NTStatus); } NTSTATUS STCInitUART( PREADER_EXTENSION ReaderExtension, BOOLEAN AutoLearn) /*++ Description: Arguments: ReaderExtension context of call Return Value: STATUS_SUCCESS error values from IFRead / IFWrite --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR Value; Value = AutoLearn ? 0x6F : 0x66; NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_UART_CONTROL, 1, &Value ); return( NTStatus ); } //---------------------------------------- END OF FILE ----------------------------------------