/*++ Copyright (c) 1998 Gemplus Development Name: gprcmd.c Description: This is the module which holds the calls to the readers functions. Environment: Kernel Mode Revision History: 06/04/99: (Y. Nadeau + M. Veillette) - Code Review 12/03/99: V1.00.005 (Y. Nadeau) - Fix Set protocol to give reader the time to process the change 18/09/98: V1.00.004 (Y. Nadeau) - Correction for NT5 beta 3 06/05/98: V1.00.003 (P. Plouidy) - Power management for NT5 10/02/98: V1.00.002 (P. Plouidy) - Plug and Play for NT5 03/07/97: V1.00.001 (P. Plouidy) - Start of development. --*/ // // Include section: // - stdio.h: standards definitons. // - ntddk.h: DDK Windows NT general definitons. // - ntdef.h: Windows NT general definitons. // #include #include #include // // - gprcmd.h: common definition for this module. // - gprnt.h: public interface definition for the NT module. // - gprelcmd.h : elementary commands profile // - gemerror.h : Gemplus error codes #include "gprnt.h" #include "gprcmd.h" #include "gprelcmd.h" // // Master driver code to load in RAM // UCHAR MASTER_DRIVER[133]={ 0xC2,0xB5,0x12,0x14,0xC6,0xFC,0x78,0x00,0x7B,0x00,0x90,0x07,0xDF,0xE0,0xD2,0xE4, 0xF0,0xEB,0xF8,0x12,0x14,0xD0,0x12,0x0D,0x9B,0x40,0x5C,0x0B,0xDC,0xF3,0xD2,0xB4, 0x90,0x07,0xDF,0xE0,0xC2,0xE4,0xF0,0x90,0x06,0xD4,0xE4,0xF5,0x15,0xF5,0x11,0xC2, 0x4D,0xA3,0x05,0x11,0x75,0x34,0x0A,0x75,0x37,0x00,0x75,0x38,0x40,0x12,0x0B,0x75, 0x20,0x20,0x3B,0xF0,0xA3,0x05,0x11,0x7B,0x01,0x12,0x0B,0x75,0x20,0x20,0x2F,0xF0, 0xA3,0x05,0x11,0x7C,0x03,0x33,0x33,0x50,0x01,0x0B,0xDC,0xFA,0x12,0x0B,0x75,0x20, 0x20,0x1C,0xF0,0xA3,0x05,0x11,0xDB,0xF4,0xE4,0x90,0x06,0xD4,0xF0,0x75,0x16,0x00, 0x75,0x15,0x00,0x12,0x14,0x15,0x22,0x74,0x0C,0x75,0x11,0x01,0x80,0xEB,0x74,0x0D, 0x75,0x11,0x01,0x80,0xE4 }; // Hard coded structure for different values of TA1. // eg. If TA= 0x92 is to set, this array of structure can be scanned and // for member variable TA1 = 0x92 and that values can be written to // approptiate location. // This is done in ConfigureTA1() function. struct tagCfgTa1 { BYTE TA1; BYTE ETU1; BYTE ETU2; BYTE ETU1P; } cfg_ta1[] = { // { 0x15, 0x01, 0x01, 0x01 }, // { 0x95, 0x01, 0x01, 0x01 }, // { 0x25, 0x03, 0x02, 0x01 }, // { 0x14, 0x05, 0x03, 0x01 }, // { 0x35, 0x05, 0x03, 0x01 }, // { 0xa5, 0x04, 0x02, 0x01 }, // { 0x94, 0x07, 0x04, 0x02 }, // { 0xb5, 0x07, 0x04, 0x02 }, // { 0x24, 0x09, 0x04, 0x04 }, // { 0x45, 0x09, 0x04, 0x04 }, { 0x13, 0x0d, 0x06, 0x09 }, { 0x34, 0x0d, 0x06, 0x09 }, { 0x55, 0x0d, 0x06, 0x09 }, { 0xa4, 0x0c, 0x06, 0x08 }, { 0xc5, 0x0c, 0x06, 0x08 }, { 0x65, 0x10, 0x08, 0x0c }, { 0x93, 0x11, 0x09, 0x0d }, { 0xb4, 0x11, 0x09, 0x0d }, { 0xd5, 0x11, 0x09, 0x0d }, { 0x23, 0x14, 0x0a, 0x10 }, { 0x44, 0x14, 0x0a, 0x10 }, { 0x12, 0x1c, 0x0e, 0x15 }, { 0x33, 0x1c, 0x0e, 0x15 }, { 0x54, 0x1c, 0x0e, 0x15 }, { 0xa3, 0x1c, 0x0f, 0x15 }, { 0xc4, 0x1c, 0x0f, 0x15 }, { 0x64, 0x24, 0x12, 0x20 }, { 0x92, 0x26, 0x14, 0x22 }, { 0xb3, 0x26, 0x14, 0x22 }, { 0xd4, 0x26, 0x14, 0x22 }, { 0x22, 0x2b, 0x16, 0x27 }, { 0x43, 0x2b, 0x16, 0x27 }, { 0x11, 0x3b, 0x1e, 0x37 }, { 0x32, 0x3b, 0x1e, 0x37 }, { 0x53, 0x3b, 0x1e, 0x37 }, // { 0x71, 0x55, 0x2b, 0x51 }, // { 0x91, 0x55, 0x2b, 0x51 }, { 0, 0, 0, 0 } }; USHORT ATRLen (UCHAR *ATR, USHORT MaxChar) /*++ Routine Description : Used to calculate the ATR length according to its content. Arguments ATR - string to analyze MaxChar - Maximum number of characters to verify. --*/ { USHORT Len; UCHAR T0; UCHAR Yi; BOOLEAN EndInterChar; BOOLEAN TCKPresent=FALSE; T0 = ATR[1]; Len= 2; // TS + T0 Yi= (T0 & 0xF0); EndInterChar = FALSE; do { if (Yi & 0x10) { Len++; //TAi } if (Yi & 0x20) { Len++; //TBi } if (Yi & 0x40) { Len++; //TCi } if (Yi & 0x80) { if (Len < MaxChar) { Yi = ATR[Len]; if((Yi & 0x0F)!=0) { TCKPresent=TRUE; } } Len++; //TDi } else { EndInterChar = TRUE; } } while((Len < MaxChar) && (EndInterChar == FALSE)); Len = Len + (T0 & 0x0F); if(TCKPresent==TRUE) { Len = Len+1; //TCK } return (Len); } BOOLEAN NeedToSwitchWithoutPTS( BYTE *ATR, DWORD LengthATR ) /*++ Routine Description : Examine if ATR identifies a specific mode (presence of TA2). Arguments ATR - string to analyze LengthATR - Length of ATR. --*/ { DWORD pos, len; // ATR[1] is T0. Examine precense of TD1. if (ATR[1] & 0x80) { // Find position of TD1. pos = 2; if (ATR[1] & 0x10) pos++; if (ATR[1] & 0x20) pos++; if (ATR[1] & 0x40) pos++; // Here ATR[pos] is TD1. Examine presence of TA2. if (ATR[pos] & 0x10) { // To be of any interest an ATR must contains at least // TS, T0, TA1, TD1, TA2 [+ T1 .. TK] [+ TCK] // Find the maximum length of uninteresting ATR. if (ATR[pos] & 0x0F) len = 5 + (ATR[1] & 0x0F); else len = 4 + (ATR[1] & 0x0F); // In protocol T=0 there is no TCK. if (LengthATR > len) // Interface bytes requires changes. if ((ATR[pos+1] & 0x10) == 0) // TA2 asks to use interface bytes. return TRUE; } } return FALSE; } NTSTATUS ValidateDriver( PSMARTCARD_EXTENSION pSmartcardExtension) /*++ Routine Description : Validate the Master driver loaded in RAM at address 2100h Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. --*/ { READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; NTSTATUS lStatus = STATUS_SUCCESS; UCHAR Vi[GPR_BUFFER_SIZE]; UCHAR To; USHORT Lo; UCHAR Vo[GPR_BUFFER_SIZE]; Vi[0] = 0x83; // DIR Vi[1] = 0x21; // ADR MSB Vi[2] = 0x00; // ADR LSB // Output variable initialisation Lo = GPR_BUFFER_SIZE; To = 0x00; Vo[0] = 0x00; // return a NTSTATUS lStatus = GprllTLVExchange ( pReaderExt, VALIDATE_DRIVER_CMD, 3, Vi, &To, &Lo, Vo ); return (lStatus); } NTSTATUS Update( PSMARTCARD_EXTENSION pSmartcardExtension, UCHAR Addr, UCHAR Value) /*++ Routine Description : Write a value in RAM Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. Addr: Address in RAM Value: Value to write --*/ { READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; NTSTATUS lStatus = STATUS_SUCCESS; UCHAR Vi[GPR_BUFFER_SIZE]; UCHAR To; USHORT Lo; UCHAR Vo[GPR_BUFFER_SIZE]; Vi[0]= 0x01; Vi[1]= Addr; Vi[2]= Value; // Output variable initialisation Lo = GPR_BUFFER_SIZE; To = 0x00; Vo[0] = 0x00; lStatus = GprllTLVExchange( pReaderExt, UPDATE_CMD, 0x03, Vi, &To, &Lo, Vo ); return (lStatus); } NTSTATUS UpdateORL( PSMARTCARD_EXTENSION pSmartcardExtension, UCHAR Addr, UCHAR Value) /*++ Routine Description : Write a value in RAM with OR mask Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. --*/ { READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; NTSTATUS lStatus = STATUS_SUCCESS; UCHAR Vi[GPR_BUFFER_SIZE]; UCHAR To; USHORT Lo; UCHAR Vo[GPR_BUFFER_SIZE]; Vi[0]= 0x02; Vi[1]= Addr; // Output variable initialisation Lo = GPR_BUFFER_SIZE; To = 0x00; Vo[0] = 0x00; lStatus = GprllTLVExchange( pReaderExt, UPDATE_CMD, 0x02, Vi, &To, &Lo, Vo ); if (STATUS_SUCCESS != lStatus) { return (lStatus); } Vi[0]= 0x01; Vi[1]= Addr; Vi[2] = Vo[1] | Value; // Output variable initialisation Lo = GPR_BUFFER_SIZE; To = 0x00; Vo[0] = 0x00; lStatus = GprllTLVExchange( pReaderExt, UPDATE_CMD, 0x03, Vi, &To, &Lo, Vo ); return (lStatus); } NTSTATUS T0toT1( PSMARTCARD_EXTENSION pSmartcardExtension) /*++ Routine Description : OS patch to put the reader in T1 mode Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. --*/ { NTSTATUS lStatus = STATUS_SUCCESS; // Verify each update to be done lStatus = Update(pSmartcardExtension,0x09,0x03); if (lStatus != STATUS_SUCCESS) { return (lStatus); } lStatus = Update(pSmartcardExtension,0x20,0x03); if (lStatus != STATUS_SUCCESS) { return (lStatus); } lStatus = Update(pSmartcardExtension,0x48,0x00); if (lStatus != STATUS_SUCCESS) { return (lStatus); } lStatus = Update(pSmartcardExtension,0x49,0x0F); if (lStatus != STATUS_SUCCESS) { return (lStatus); } lStatus = Update(pSmartcardExtension,0x4A,0x20); if (lStatus != STATUS_SUCCESS) { return (lStatus); } lStatus = Update(pSmartcardExtension,0x4B,0x0B); if (lStatus != STATUS_SUCCESS) { return (lStatus); } lStatus = Update(pSmartcardExtension,0x4C,0x40); if (lStatus != STATUS_SUCCESS) { return (lStatus); } lStatus = UpdateORL(pSmartcardExtension,0x2A,0x02); if (lStatus != STATUS_SUCCESS) { return (lStatus); } // Give the reader the time to process the change GprllWait(100); return (STATUS_SUCCESS); } NTSTATUS T1toT0( PSMARTCARD_EXTENSION pSmartcardExtension) /*++ Routine Description : OS patch to put the reader in T0 mode Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. --*/ { READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; NTSTATUS lStatus = STATUS_SUCCESS; lStatus = Update(pSmartcardExtension,0x09,0x02); if (lStatus != STATUS_SUCCESS) { return (lStatus); } lStatus = Update(pSmartcardExtension,0x20,0x02); if (lStatus != STATUS_SUCCESS) { return (lStatus); } // Give the reader the time to process the change GprllWait(100); return (STATUS_SUCCESS); } NTSTATUS IccColdReset( PSMARTCARD_EXTENSION pSmartcardExtension ) /*++ Routine Description : Cold reset function. The delay between the power down & the power up is strored in the PowerTimeout field of the READER_EXTENSION structure. The default value is 0. Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. --*/ { // // Local variables: // - pReaderExt holds the pointer to the current ReaderExtension structure // - lStatus holds the status to return. // - Vi Holds the input buffer of the TLV commnand. // - To holds the Tag of the returned TLV. // - Lo holds the Length of the buffer of the returned TLV. // - Vo holds the Buffer of the returned TLV. // - RespLen holds the Length of the buffer of the TLV returned by the power up command. // - Rbuff holds the buffer of the TLV returned by the power up command. // READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; NTSTATUS lStatus = STATUS_SUCCESS; UCHAR Vi[GPR_BUFFER_SIZE]; UCHAR To; USHORT Lo; UCHAR Vo[GPR_BUFFER_SIZE]; USHORT RespLen; UCHAR RespBuff[GPR_BUFFER_SIZE]; UCHAR BWTimeAdjust; USHORT MaxChar; // Send power on command (GprllTLVExchange: T= 20h, L = 0) // <= response // Output variable initialisation RespLen = GPR_BUFFER_SIZE; To = 0x00; RespBuff[0] = 0x00; lStatus = GprllTLVExchange( pReaderExt, OPEN_SESSION_CMD, 0x00, Vi, &To, &RespLen, RespBuff ); if (lStatus != STATUS_SUCCESS) { return (lStatus); } // Correct the WTX pb // Get the value set by the reader Vi [0]=0x02; Vi [1]=0x4A; // Output variable initialisation Lo = GPR_BUFFER_SIZE; To = 0x00; Vo[0] = 0x00; lStatus = GprllTLVExchange( pReaderExt, UPDATE_CMD, 0x02, Vi, &To, &Lo, Vo ); if (lStatus != STATUS_SUCCESS) { return (lStatus); } // adjust the value of the BWT if(Vo[1] >= 0x80) { BWTimeAdjust = 0xff; } else { BWTimeAdjust = Vo[1] * 2; } lStatus = Update(pSmartcardExtension,0x4A,BWTimeAdjust); if (lStatus == STATUS_SUCCESS) { // Get the ATR length from this function MaxChar = RespLen - 1; RespLen = ATRLen(RespBuff+1, MaxChar) + 1; // // Copy ATR to smart card struct (remove the reader status byte) // The lib needs the ATR for evaluation of the card parameters // // Verification if Response buffer is larger than ATR buffer. // if ( (pSmartcardExtension->SmartcardReply.BufferSize >= (ULONG) (RespLen - 1)) && (sizeof(pSmartcardExtension->CardCapabilities.ATR.Buffer) >= (ULONG)(RespLen - 1)) ) { RtlCopyMemory( pSmartcardExtension->SmartcardReply.Buffer, RespBuff + 1, RespLen - 1 ); pSmartcardExtension->SmartcardReply.BufferLength = (ULONG) (RespLen - 1); RtlCopyMemory( pSmartcardExtension->CardCapabilities.ATR.Buffer, pSmartcardExtension->SmartcardReply.Buffer, pSmartcardExtension->SmartcardReply.BufferLength ); pSmartcardExtension->CardCapabilities.ATR.Length = (UCHAR) pSmartcardExtension->SmartcardReply.BufferLength ; pSmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED; // Parse the ATR string in order to check if it as valid // and to find out if the card uses invers convention lStatus = SmartcardUpdateCardCapabilities(pSmartcardExtension); if (lStatus == STATUS_SUCCESS) { RtlCopyMemory( pSmartcardExtension->IoRequest.ReplyBuffer, pSmartcardExtension->CardCapabilities.ATR.Buffer, pSmartcardExtension->CardCapabilities.ATR.Length ); *pSmartcardExtension->IoRequest.Information = pSmartcardExtension->SmartcardReply.BufferLength; // // Implicite protocol and parameters selection? // Verify if TA2 require to switch in TA1 // if ( NeedToSwitchWithoutPTS( pSmartcardExtension->CardCapabilities.ATR.Buffer, pSmartcardExtension->CardCapabilities.ATR.Length) == FALSE) { // send reader parameters IfdConfig(pSmartcardExtension, 0x11); } } } else { lStatus = STATUS_BUFFER_TOO_SMALL; } } return (lStatus); } NTSTATUS IccPowerDown( PSMARTCARD_EXTENSION pSmartcardExtension ) /*++ Routine Description : ICC power down function Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. --*/ { // Local variables: // - pReaderExt holds the pointer to the current ReaderExtension structure // - lStatus holds the status to return. // - Vi Holds the input buffer of the TLV commnand. // - To holds the Tag of the returned TLV. // - Lo holds the Length of the buffer of the returned TLV. // - Vo holds the Buffer of the returned TLV. READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; NTSTATUS lStatus = STATUS_SUCCESS; UCHAR Vi[GPR_BUFFER_SIZE]; UCHAR To; USHORT Lo; UCHAR Vo[GPR_BUFFER_SIZE]; KIRQL irql; // Power down // Output variable initialisation Lo = GPR_BUFFER_SIZE; To = 0x00; Vo[0] = 0x00; lStatus = GprllTLVExchange( pReaderExt, CLOSE_SESSION_CMD, 0x00, Vi, &To, &Lo, Vo ); if (lStatus == STATUS_SUCCESS) { KeAcquireSpinLock(&pSmartcardExtension->OsData->SpinLock, &irql); pSmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SWALLOWED; KeReleaseSpinLock(&pSmartcardExtension->OsData->SpinLock, irql); } return (lStatus); } NTSTATUS IccIsoOutput( PSMARTCARD_EXTENSION pSmartcardExtension, const UCHAR pCommand[5], USHORT *pRespLen, UCHAR pRespBuff[] ) /*++ Routine Description : This function sends an ISO OUT command to the card Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. pCommand : Iso out command to send. pRespLen : in - maximum buffer size available out - returned buffer length. pRespBuff: returned buffer --*/ { // Local variables: // - pReaderExt holds the pointer to the current ReaderExtension structure // - lStatus holds the status to return. // - Vi Holds the input buffer of the TLV commnand. // - To holds the Tag of the returned TLV. // - Lo holds the Length of the buffer of the returned TLV. // - Vo holds the Buffer of the returned TLV. READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; NTSTATUS lStatus = STATUS_SUCCESS; UCHAR Vi[GPR_BUFFER_SIZE]= { 0x01 }; UCHAR To; USHORT Lo; UCHAR Vo[GPR_BUFFER_SIZE]; // The five command bytes are added in cmd buffer. RtlCopyMemory(Vi + 1, pCommand, 5); // The command is send to IFD. // Fields RespLen and RespBuff are updates // <= sResponse Lo = *pRespLen; To = 0x00; Vo[0] = 0x00; lStatus = GprllTLVExchange( pReaderExt, APDU_EXCHANGE_CMD, 6, Vi, &To, &Lo, Vo ); if (lStatus != STATUS_SUCCESS) { *pRespLen = 0; } else { // To correct the bug of GPR400 version 1.0 // If the response is 0xE7 then correct the response if ( (Lo != 1) && (pReaderExt->OsVersion<= 0x10 )&& (Vo[0]==0xE7) ) { Lo = 0x03; } RtlCopyMemory(pRespBuff, Vo, Lo); *pRespLen = Lo; } return (lStatus); } NTSTATUS IccIsoInput( PSMARTCARD_EXTENSION pSmartcardExtension, const UCHAR pCommand[5], const UCHAR pData[], USHORT *pRespLen, BYTE pRespBuff[] ) /*++ Routine Description : This function sends an ISO IN command to the card Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. pCommand : Iso out command to send. pData : data to send. pRespLen : in - maximum buffer size available out - returned buffer length. pRespBuff: returned buffer --*/ { // Local variables: // - pReaderExt holds the pointer to the current ReaderExtension structure // - Ti holds the apdu command tag. // - Li holds the Iso out command length. // - Vi holds Icc ISO In command whose format is // [ Data ] // Length = Length + Dir + CLA + INS + P1 + P2 // - To holds the response tag // - Lo holds th response buffer length. // - Vo holds the response buffer READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; UCHAR Vi[GPR_BUFFER_SIZE] = { 0x00 }; UCHAR Ti = APDU_EXCHANGE_CMD; UCHAR To; UCHAR Vo[GPR_BUFFER_SIZE]; USHORT Li; USHORT Lo; NTSTATUS lStatus=STATUS_SUCCESS; // Length of the the TLV = Length of data + 6 Li = pCommand[4]+6, // The five command bytes are added in cmd buffer. RtlCopyMemory(Vi + 1, pCommand, 5); //The data field is added. RtlCopyMemory(Vi + 6, pData, pCommand[4]); // The command is send to IFD. // Fields RespLen and RespBuff are updates // <= sResponse Lo = *pRespLen; lStatus = GprllTLVExchange( pReaderExt, Ti, Li, Vi, &To, &Lo, Vo ); if (lStatus == STATUS_SUCCESS) { *pRespLen = Lo; RtlCopyMemory(pRespBuff, Vo, Lo); } else { *pRespLen = 0; } return (lStatus); } NTSTATUS IccIsoT1( PSMARTCARD_EXTENSION pSmartcardExtension, const USHORT Li, const UCHAR Vi[], USHORT *Lo, UCHAR Vo[] ) /*++ Routine Description : This function sends a T=1 frame to the card Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. Li : Length of the frame to send. Vi : frame to send. Lo : in - maximum buffer size available out - Length of the response buffer. Vo : Response buffer. --*/ { // Local variables: // - pReaderExt holds the pointer to the current ReaderExtension structure // - Ti Tag in TLV structure to send. // - To Tag in response TLV structure. UCHAR Ti = APDU_EXCHANGE_CMD; UCHAR To; NTSTATUS lStatus = STATUS_SUCCESS; READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; To = 0x00; // Return value for To is not needed, The function GprllTLVExchange verify that // it corresponds to the Ti lStatus = GprllTLVExchange( pReaderExt, Ti, Li, Vi, &To, Lo, Vo ); return (lStatus); } NTSTATUS IfdConfig( PSMARTCARD_EXTENSION pSmartcardExtension, UCHAR TA1 ) /*++ Routine Description : This function Sets the correct internal values of the reader regarding the TA1 of the ATR. Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. --*/ { // Local variables: // - sResponse holds the called function responses. // - pReaderExt holds the pointer to the current ReaderExtension structure // - lStatus holds the status to return. // - Vi Holds the input buffer of the TLV commnand. // - To holds the Tag of the returned TLV. // - Lo holds the Length of the buffer of the returned TLV. // - Vo holds the Buffer of the returned TLV. // UCHAR Card_ETU1; UCHAR Card_ETU2; UCHAR Card_ETU1P; UCHAR Card_TA1; READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; NTSTATUS lStatus = STATUS_SUCCESS; USHORT i = 0; // search TA1 parameters do { if ( TA1 == cfg_ta1[i].TA1 ) { break; } i++; } while ( cfg_ta1[i].TA1 != 0 ); if(cfg_ta1[i].TA1 != 0) { Card_TA1 = cfg_ta1[i].TA1; Card_ETU1 = cfg_ta1[i].ETU1; Card_ETU2 = cfg_ta1[i].ETU2; Card_ETU1P= cfg_ta1[i].ETU1P; } else { // Default value 9600 Card_TA1 = 0x11; Card_ETU1 = 0x3B; Card_ETU2 = 0x1E; Card_ETU1P= 0x37; } // Verify each update to be done //Set the TA1 lStatus = Update(pSmartcardExtension,0x32,Card_TA1); if (lStatus != STATUS_SUCCESS) { return (lStatus); } //Set the Card ETU1 lStatus = Update(pSmartcardExtension,0x35,Card_ETU1); if (lStatus != STATUS_SUCCESS) { return (lStatus); } //Set the Card ETU2 lStatus = Update(pSmartcardExtension,0x36,Card_ETU2); if (lStatus != STATUS_SUCCESS) { return (lStatus); } //Set the Card ETU1 P lStatus = Update(pSmartcardExtension,0x39,Card_ETU1P); if (lStatus != STATUS_SUCCESS) { return (lStatus); } //Set the Save TA1 lStatus = Update(pSmartcardExtension,0x3A,Card_TA1); if (lStatus != STATUS_SUCCESS) { return (lStatus); } //Set the Save ETU1 lStatus = Update(pSmartcardExtension,0x3D,Card_ETU1); if (lStatus != STATUS_SUCCESS) { return (lStatus); } //Set the Save ETU2 lStatus = Update(pSmartcardExtension,0x3E,Card_ETU2); if (lStatus != STATUS_SUCCESS) { return (lStatus); } //Set the Save ETU1 P lStatus = Update(pSmartcardExtension,0x41,Card_ETU1P); if (lStatus != STATUS_SUCCESS) { return (lStatus); } // Give the reader the time to process the change GprllWait(100); return (STATUS_SUCCESS); } NTSTATUS IfdCheck( PSMARTCARD_EXTENSION pSmartcardExtension ) /*++ Routine Description : This function performs a software reset of the GPR400 using the Handshake register and TEST if hardware okay. Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. --*/ { // Local variables: // - pReaderExt holds the pointer to the current ReaderExtension structure // - HandShakeRegister // READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; UCHAR HandShakeRegister; #if DBG SmartcardDebug( DEBUG_ERROR, ( "%s!IfdCheck: Enter\n", SC_DRIVER_NAME) ); #endif // In the case that system reboot for Hibernate in // Power management. The GPR400 signal a device was been remove // but we have to request a second time to have the actual // state of the reader. HandShakeRegister = GprllReadRegister(pReaderExt,REGISTER_HANDSHAKE); SmartcardDebug( DEBUG_DRIVER, ("%s!IfdCheck: Read HandShakeRegister value:%x\n", SC_DRIVER_NAME, HandShakeRegister) ); //Set to 1 the Master Reset bit from Handshake register GprllMaskHandshakeRegister(pReaderExt,0x01,1); //Wait 10 ms GprllWait(10); //Reset the Master Reset bit from Handshake register GprllMaskHandshakeRegister(pReaderExt,0x01,0); //Wait 80 ms GprllWait(80); HandShakeRegister = GprllReadRegister(pReaderExt,REGISTER_HANDSHAKE); SmartcardDebug( DEBUG_DRIVER, ("%s!IfdCheck: Read HandShakeRegister 2nd time value:%x\n", SC_DRIVER_NAME, HandShakeRegister) ); if(HandShakeRegister != 0x80) { // Return reader IO problem return (STATUS_IO_DEVICE_ERROR); } return (STATUS_SUCCESS); } NTSTATUS IfdReset( PSMARTCARD_EXTENSION pSmartcardExtension ) /*++ Routine Description : This function performs a software reset of the GPR400 using the Handshake register. Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. --*/ { // Local variables: // - sResponse holds the called function responses. // - pReaderExt holds the pointer to the current ReaderExtension structure // - lStatus holds the status to return. // - Vi Holds the input buffer of the TLV commnand. // - To holds the Tag of the returned TLV. // - Lo holds the Length of the buffer of the returned TLV. // - Vo holds the Buffer of the returned TLV. READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; NTSTATUS lStatus = STATUS_SUCCESS; UCHAR Vi[GPR_BUFFER_SIZE]; UCHAR To; USHORT Lo; UCHAR Vo[GPR_BUFFER_SIZE]; #if DBG SmartcardDebug( DEBUG_TRACE, ( "%s!IfdReset: Enter\n", SC_DRIVER_NAME) ); #endif // In the case that system reboot for Hibernate in // Power management. The GPR400 signal a device was been remove // but we have to request a second time to have the actual // state of the reader. //Set to 1 the Master Reset bit from Handshake register GprllMaskHandshakeRegister(pReaderExt,0x01,1); //Wait 10 ms GprllWait(10); //Reset the Master Reset bit from Handshake register GprllMaskHandshakeRegister(pReaderExt,0x01,0); //Wait 80 ms GprllWait(80); //Read the GPR status Vi[0] = 0x00; Lo = GPR_BUFFER_SIZE; lStatus = GprllTLVExchange ( pReaderExt, CHECK_AND_STATUS_CMD, 0x01, Vi, &To, &Lo, Vo ); #if DBG SmartcardDebug( DEBUG_TRACE, ( "%s!IfdReset: GprllTLVExchange status= %x\n", SC_DRIVER_NAME, lStatus) ); #endif if (lStatus != STATUS_SUCCESS) { SmartcardDebug( DEBUG_TRACE, ( "%s!IfdReset: GprllTLVExchange() failed! Leaving.....\n", SC_DRIVER_NAME) ); return (lStatus); } //Memorize the GPR400 version pReaderExt->OsVersion = Vo[1]; pSmartcardExtension->VendorAttr.IfdVersion.VersionMinor = pReaderExt->OsVersion & 0x0f; pSmartcardExtension->VendorAttr.IfdVersion.VersionMajor = (pReaderExt->OsVersion & 0xf0) >> 4; SmartcardDebug( DEBUG_TRACE, ( "%s!IfdReset: Loading Master driver...\n", SC_DRIVER_NAME) ); //Load the Master Driver in RAM at @2100h Vi[0] = 0x02; // DIR Vi[1] = 0x01 ; // ADR MSB Vi[2] = 0x00 ; // ADR LSB memcpy(&Vi[3], MASTER_DRIVER, sizeof(MASTER_DRIVER)); // Output variable initialisation Lo = GPR_BUFFER_SIZE; To = 0x00; Vo[0] = 0x00; lStatus = GprllTLVExchange ( pReaderExt, LOAD_MEMORY_CMD, sizeof(MASTER_DRIVER) + 3, Vi, &To, &Lo, Vo ); if (lStatus != STATUS_SUCCESS) { SmartcardDebug( DEBUG_TRACE, ( "%s!IfdReset: GprllTLVExchange() failed! Leaving.....\n", SC_DRIVER_NAME) ); return (lStatus); } lStatus = ValidateDriver(pSmartcardExtension); if (lStatus != STATUS_SUCCESS) { SmartcardDebug( DEBUG_TRACE, ( "%s!IfdReset: ValidateDriver() failed! Leaving.....\n", SC_DRIVER_NAME) ); return (lStatus); } return (STATUS_SUCCESS); } NTSTATUS IfdPowerDown( PSMARTCARD_EXTENSION pSmartcardExtension ) /*++ Routine Description : This function powers down the IFD Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. --*/ { // Local variables: // - sResponse holds the called function responses. // - pReaderExt holds the pointer to the current ReaderExtension structure // - lStatus holds the status to return. // - Vi Holds the input buffer of the TLV commnand. // - To holds the Tag of the returned TLV. // - Lo holds the Length of the buffer of the returned TLV. // - Vo holds the Buffer of the returned TLV. READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; NTSTATUS lStatus = STATUS_SUCCESS; UCHAR Vi[GPR_BUFFER_SIZE]; UCHAR To; USHORT Lo; UCHAR Vo[GPR_BUFFER_SIZE]; // Put the GPR in Power-down mode (GprllTLVExchange T=0x40, L=1 and V=0x00) // <== response of the GprllTLVExchange Vi[0] = 0x00; // Output variable initialisation Lo = GPR_BUFFER_SIZE; To = 0x00; Vo[0] = 0x00; lStatus = GprllTLVExchange( pReaderExt, POWER_DOWN_GPR_CMD, 0x01, Vi, &To, &Lo, Vo ); return (lStatus); } NTSTATUS GprCbReaderPower( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ Routine Description : This function is called by the Smart card library when a IOCTL_SMARTCARD_POWER occurs. This function provides 3 differents functionnality, depending of the minor IOCTL value - Cold reset (SCARD_COLD_RESET), - Warm reset (SCARD_WARM_RESET), - Power down (SCARD_POWER_DOWN). Arguments - SmartcardExtension is a pointer on the SmartCardExtension structure of the current device. --*/ { NTSTATUS lStatus = STATUS_SUCCESS; PREADER_EXTENSION pReader; ASSERT(SmartcardExtension != NULL); pReader = SmartcardExtension->ReaderExtension; waitForIdleAndBlock(pReader); switch(SmartcardExtension->MinorIoControlCode) { case SCARD_POWER_DOWN: //Power down the ICC lStatus = IccPowerDown(SmartcardExtension); break; case SCARD_COLD_RESET: // Power up the ICC after a power down and a PowerTimeout waiting time. lStatus = IccPowerDown(SmartcardExtension); if(lStatus != STATUS_SUCCESS) { break; } // Waits for the Power Timeout to be elapsed before the reset command. GprllWait(SmartcardExtension->ReaderExtension->PowerTimeOut); case SCARD_WARM_RESET: lStatus = IccColdReset(SmartcardExtension); break; default: lStatus = STATUS_NOT_SUPPORTED; } setIdle(pReader); return lStatus; } NTSTATUS GprCbTransmit( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ Routine Description : This function is called by the Smart card library when a IOCTL_SMARTCARD_TRANSMIT occurs. This function is used to transmit a command to the card. Arguments - SmartcardExtension is a pointer on the SmartCardExtension structure of the current device. --*/ { NTSTATUS lStatus=STATUS_SUCCESS; PUCHAR requestBuffer = SmartcardExtension->SmartcardRequest.Buffer; PUCHAR replyBuffer = SmartcardExtension->SmartcardReply.Buffer; PULONG requestLength = &SmartcardExtension->SmartcardRequest.BufferLength; PULONG replyLength = &SmartcardExtension->SmartcardReply.BufferLength; USHORT sRespLen; UCHAR pRespBuff[GPR_BUFFER_SIZE]; PREADER_EXTENSION pReader; ASSERT(SmartcardExtension != NULL); *requestLength = 0; sRespLen = 0; pRespBuff[0] = 0x0; pReader = SmartcardExtension->ReaderExtension; waitForIdleAndBlock(pReader); switch (SmartcardExtension->CardCapabilities.Protocol.Selected) { // Raw case SCARD_PROTOCOL_RAW: lStatus = STATUS_INVALID_DEVICE_STATE; break; // T=0 case SCARD_PROTOCOL_T0: lStatus = SmartcardT0Request(SmartcardExtension); if (lStatus != STATUS_SUCCESS) { setIdle(pReader); return lStatus; } sRespLen = GPR_BUFFER_SIZE; pRespBuff[0] = 0x0; if (SmartcardExtension->T0.Le > 0) { // ISO OUT command if BufferLength = 5 lStatus = IccIsoOutput( SmartcardExtension, ( UCHAR *) SmartcardExtension->SmartcardRequest.Buffer, &sRespLen, pRespBuff ); } else { // ISO IN command if BufferLength >5 or BufferLength = 4 lStatus = IccIsoInput( SmartcardExtension, ( UCHAR *) SmartcardExtension->SmartcardRequest.Buffer, ( UCHAR *) SmartcardExtension->SmartcardRequest.Buffer+5, &sRespLen, pRespBuff ); } if (lStatus != STATUS_SUCCESS) { setIdle(pReader); return lStatus; } // Copy the response command without the reader status // Verify if the buffer is large enough if (SmartcardExtension->SmartcardReply.BufferSize >= (ULONG)(sRespLen - 1)) { RtlCopyMemory( SmartcardExtension->SmartcardReply.Buffer, pRespBuff + 1, sRespLen - 1); SmartcardExtension->SmartcardReply.BufferLength = (ULONG) (sRespLen - 1); } else { // SmartcardT0Reply must be called; prepare this call. SmartcardExtension->SmartcardReply.BufferLength = 0; } lStatus = SmartcardT0Reply(SmartcardExtension); break; // T=1 case SCARD_PROTOCOL_T1: do { SmartcardExtension->SmartcardRequest.BufferLength = 0; lStatus = SmartcardT1Request(SmartcardExtension); if(lStatus != STATUS_SUCCESS) { setIdle(pReader); return lStatus; } sRespLen = GPR_BUFFER_SIZE; pRespBuff[0] = 0x0; lStatus = IccIsoT1( SmartcardExtension, (USHORT) SmartcardExtension->SmartcardRequest.BufferLength, (UCHAR *) SmartcardExtension->SmartcardRequest.Buffer, &sRespLen, pRespBuff); if(lStatus != STATUS_SUCCESS) { // do not try to access the reader anymore. if(lStatus == STATUS_DEVICE_REMOVED) { setIdle(pReader); return lStatus; } // Let the SmartcardT1Reply determine the status sRespLen = 1; } // Copy the response of the reader in the reply buffer // Remove the status of the reader // Verify if the buffer is large enough if (SmartcardExtension->SmartcardReply.BufferSize >= (ULONG)(sRespLen - 1)) { RtlCopyMemory( SmartcardExtension->SmartcardReply.Buffer, pRespBuff + 1 , sRespLen - 1 ); SmartcardExtension->SmartcardReply.BufferLength = (ULONG) sRespLen - 1; } else { // SmartcardT1Reply must be called; prepare this call. SmartcardExtension->SmartcardReply.BufferLength = 0; } lStatus = SmartcardT1Reply(SmartcardExtension); } while(lStatus == STATUS_MORE_PROCESSING_REQUIRED); break; default: lStatus = STATUS_INVALID_DEVICE_REQUEST; break; } setIdle(pReader); return lStatus; } NTSTATUS GprCbSetProtocol( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ Routine Description : This function is called by the Smart card library when a IOCTL_SMARTCARD_SET_PROTOCOL occurs. The minor IOCTL value holds the protocol to set. Arguments - SmartcardExtension is a pointer on the SmartCardExtension structure of the current device. --*/ { NTSTATUS lStatus=STATUS_SUCCESS; UCHAR Vi[GPR_BUFFER_SIZE]; UCHAR To; USHORT Lo; UCHAR Vo[GPR_BUFFER_SIZE]; READER_EXTENSION *pReaderExt = SmartcardExtension->ReaderExtension; UCHAR PTS0=0; UCHAR Value = 0; PREADER_EXTENSION pReader; KIRQL irql; ASSERT(SmartcardExtension != NULL); pReader = SmartcardExtension->ReaderExtension; waitForIdleAndBlock(pReader); // Check if the card is already in specific state // and if the caller wants to have the already selected protocol. // We return success if this is the case. // *SmartcardExtension->IoRequest.Information = 0x00; if ( SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC && ( SmartcardExtension->CardCapabilities.Protocol.Selected & SmartcardExtension->MinorIoControlCode ) ) { lStatus = STATUS_SUCCESS; } else { __try { if (SmartcardExtension->CardCapabilities.Protocol.Supported & SmartcardExtension->MinorIoControlCode & SCARD_PROTOCOL_T1) { // select T=1 SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T1; PTS0= 0x11; } else if (SmartcardExtension->CardCapabilities.Protocol.Supported & SmartcardExtension->MinorIoControlCode & SCARD_PROTOCOL_T0) { // select T=0 SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T0; PTS0 = 0x10; } else { lStatus = STATUS_INVALID_DEVICE_REQUEST; __leave; } // Send the PTS function Vi[0] = 0xFF; Vi[1] = PTS0; Vi[2] = SmartcardExtension->CardCapabilities.PtsData.Fl <<4 | SmartcardExtension->CardCapabilities.PtsData.Dl; Vi[3] = (0xFF ^ PTS0) ^ Vi[2]; Lo = GPR_BUFFER_SIZE; To = 0x00; Vo[0] = 0x00; // Status of the PTS could be STATUS SUCCESS // or STATUS_DEVICE_PROTOCOL_ERROR if failed. lStatus = GprllTLVExchange( pReaderExt, EXEC_MEMORY_CMD, 0x04, Vi, &To, &Lo, Vo ); #if DBG SmartcardDebug( DEBUG_TRACE, ( "%s!IfdReset: GprCbSetProtocol status= %x\n", SC_DRIVER_NAME, lStatus) ); #endif if (lStatus != STATUS_SUCCESS) { __leave; } // reader should reply status byte of 00 or 12 // the rest is other problem with no relation with // the PTS negociation lStatus = STATUS_SUCCESS; // Put the reader in the right protocol if (SmartcardExtension->CardCapabilities.Protocol.Selected == SCARD_PROTOCOL_T1) { lStatus = T0toT1(SmartcardExtension); } else { lStatus = T1toT0(SmartcardExtension); } if (lStatus != STATUS_SUCCESS) { __leave; } lStatus = IfdConfig(SmartcardExtension, 0x11); if (lStatus != STATUS_SUCCESS) { __leave; } } // we change the error code to a protocol error. __finally { if (lStatus != STATUS_SUCCESS && lStatus != STATUS_INVALID_DEVICE_REQUEST ) { lStatus = STATUS_DEVICE_PROTOCOL_ERROR; } } } // // Set the reply buffer length to sizeof(ULONG). // Check if status SUCCESS, store the selected protocol. // KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, &irql); if (lStatus == STATUS_SUCCESS) { *SmartcardExtension->IoRequest.Information = sizeof(SmartcardExtension->CardCapabilities.Protocol.Selected); *( PULONG) SmartcardExtension->IoRequest.ReplyBuffer = SmartcardExtension->CardCapabilities.Protocol.Selected; SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC; } else { SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED; *SmartcardExtension->IoRequest.Information = 0; } KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, irql); setIdle(pReader); return lStatus; } NTSTATUS AskForCardPresence( PSMARTCARD_EXTENSION pSmartcardExtension ) /*++ Routine Description : This functions send a TLV command to the reader to know if there is a card inserted. The function does not wait to the answer. The treatment of the answer is done in the interrupt routine. Arguments pSmartcardExtension: Pointer to the SmartcardExtension structure. --*/ { // Local variables: // - pReaderExt holds the pointer to the current ReaderExtension structure // - V holds the value for the TLV comand. READER_EXTENSION *pReaderExt = pSmartcardExtension->ReaderExtension; UCHAR V=0x02; GprllSendCmd(pReaderExt,CHECK_AND_STATUS_CMD,1,&V); return (STATUS_SUCCESS); } NTSTATUS SpecificTag( PSMARTCARD_EXTENSION SmartcardExtension, DWORD IoControlCode, DWORD BufferInLen, BYTE *BufferIn, DWORD BufferOutLen, BYTE *BufferOut, DWORD *LengthOut ) /*++ Routine Description : This function is called when a specific Tag request occurs. Arguments - SmartcardExtension is a pointer on the SmartCardExtension structure of the current device. - IoControlCode holds the IOCTL value. --*/ { ULONG TagValue; PREADER_EXTENSION pReaderExtension = SmartcardExtension->ReaderExtension; //Set the reply buffer length to 0. *LengthOut = 0; //Verify the length of the Tag //<== STATUS_BUFFER_TOO_SMALL if (BufferInLen < (DWORD) sizeof(TagValue)) { return(STATUS_BUFFER_TOO_SMALL); } TagValue = (ULONG) *((PULONG)BufferIn); //Switch for the different IOCTL: //Get the value of one tag (IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE) //Switch for the different Tags: switch(IoControlCode) { case IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE: switch (TagValue) { // Power Timeout (SCARD_ATTR_SPEC_POWER_TIMEOUT) // Verify the length of the output buffer. // <== STATUS_BUFFER_TOO_SMALL // Update the output buffer and the length. // <== STATUS_SUCCESS case SCARD_ATTR_SPEC_POWER_TIMEOUT: if ( BufferOutLen < (DWORD) sizeof(pReaderExtension->PowerTimeOut)) { return(STATUS_BUFFER_TOO_SMALL); } ASSERT(BufferOut != 0); memcpy( BufferOut, &pReaderExtension->PowerTimeOut, sizeof(pReaderExtension->PowerTimeOut) ); *(LengthOut) = (ULONG) sizeof(pReaderExtension->PowerTimeOut); return STATUS_SUCCESS; break; // Command Timeout (SCARD_ATTR_SPEC_CMD_TIMEOUT) // Verify the length of the output buffer. // <== STATUS_BUFFER_TOO_SMALL // Update the output buffer and the length. // <== STATUS_SUCCESS case SCARD_ATTR_SPEC_CMD_TIMEOUT: if (BufferOutLen < (DWORD) sizeof(pReaderExtension->CmdTimeOut)) { return(STATUS_BUFFER_TOO_SMALL); } ASSERT(BufferOut != 0); memcpy( BufferOut, &pReaderExtension->CmdTimeOut, sizeof(pReaderExtension->CmdTimeOut) ); *(LengthOut) = (ULONG) sizeof(pReaderExtension->CmdTimeOut); return STATUS_SUCCESS; break; case SCARD_ATTR_MANUFACTURER_NAME: if (BufferOutLen < ATTR_LENGTH) { return STATUS_BUFFER_TOO_SMALL; } // Copy the string of the Manufacturer Name memcpy( BufferOut, ATTR_MANUFACTURER_NAME, sizeof(ATTR_MANUFACTURER_NAME) ); *(LengthOut) = (ULONG)sizeof(ATTR_MANUFACTURER_NAME); return STATUS_SUCCESS; break; case SCARD_ATTR_ORIGINAL_FILENAME: if (BufferOutLen < ATTR_LENGTH) { return STATUS_BUFFER_TOO_SMALL; } // Copy the string of the Original file name of the current driver memcpy( BufferOut, ATTR_ORIGINAL_FILENAME, sizeof(ATTR_ORIGINAL_FILENAME) ); *(LengthOut) = (ULONG)sizeof(ATTR_ORIGINAL_FILENAME); return STATUS_SUCCESS; break; // Unknown tag // <== STATUS_NOT_SUPPORTED default: return STATUS_NOT_SUPPORTED; break; } break; // Set the value of one tag (IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE) // Switch for the different Tags: case IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE: switch (TagValue) { // Power Timeout (SCARD_ATTR_SPEC_POWER_TIMEOUT) // Verify the length of the input buffer. // <== STATUS_BUFFER_TOO_SMALL // Update the value. // <== STATUS_SUCCESS case SCARD_ATTR_SPEC_POWER_TIMEOUT: if ( BufferInLen < (DWORD) (sizeof(pReaderExtension->PowerTimeOut) + sizeof(TagValue)) ) { return(STATUS_BUFFER_TOO_SMALL); } ASSERT(BufferIn !=0); memcpy( &pReaderExtension->PowerTimeOut, BufferIn + sizeof(TagValue), sizeof(pReaderExtension->PowerTimeOut) ); return STATUS_SUCCESS; break; // Command Timeout (SCARD_ATTR_SPEC_CMD_TIMEOUT) // Verify the length of the input buffer. // <== STATUS_BUFFER_TOO_SMALL // Update the value. // <== STATUS_SUCCESS case SCARD_ATTR_SPEC_CMD_TIMEOUT: if ( BufferInLen < (DWORD) ( sizeof(pReaderExtension->CmdTimeOut) + sizeof(TagValue)) ) { return(STATUS_BUFFER_TOO_SMALL); } ASSERT(BufferIn != 0); memcpy( &pReaderExtension->CmdTimeOut, BufferIn + sizeof(TagValue), sizeof(pReaderExtension->CmdTimeOut) ); return STATUS_SUCCESS; break; // Unknown tag // <== STATUS_NOT_SUPPORTED default: return STATUS_NOT_SUPPORTED; } break; default: return STATUS_NOT_SUPPORTED; } } NTSTATUS SwitchSpeed( PSMARTCARD_EXTENSION SmartcardExtension, ULONG BufferInLen, PUCHAR BufferIn, ULONG BufferOutLen, PUCHAR BufferOut, PULONG LengthOut ) /*++ Routine Description: This function is called when apps want to switch reader speed after a proprietary switch speed (switch protocol) command has been sent to the smart card. Arguments: SmartcardExtension - is a pointer on the SmartCardExtension structure of the current device. BufferInLen - holds the length of the input data. BufferIn - holds the input data. TA1. If 0 BufferOutLen - holds the size of the output buffer. BufferOut - the output buffer. Reader status code. LengthOut - holds the length of the output data. Return Value: STATUS_SUCCESS - We could execute the request. STATUS_BUFFER_TOO_SMALL - The output buffer is to small. STATUS_NOT_SUPPORTED - We could not support the Ioctl specified. --*/ { NTSTATUS status; BYTE NewTA1; ULONG i; ASSERT(SmartcardExtension != NULL); *LengthOut = 0; // Just checking if IOCTL exists. if (BufferInLen == 0) { SmartcardDebug( DEBUG_INFO, ("%s!SwitchSpeed: Just checking IOCTL.\n", SC_DRIVER_NAME) ); return(STATUS_SUCCESS); } else { NewTA1 = BufferIn[0]; i = 0; // Verify if this TA1 is support by the GPR400 do { if ( NewTA1 == cfg_ta1[i].TA1 ) { // TA1 Found! break; } i++; } while ( cfg_ta1[i].TA1 != 0 ); } // If 0 means TA1 not found if(cfg_ta1[i].TA1 != 0) { SmartcardDebug( DEBUG_INFO, ("%s!GDDK_0ASwitchSpeed: 0x%X\n", SC_DRIVER_NAME, NewTA1) ); status = IfdConfig(SmartcardExtension, NewTA1); } else { // TA1 not supported return STATUS_NOT_SUPPORTED; } return status; } NTSTATUS GprCbVendorIoctl( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ Routine Description : This routine is called when a vendor IOCTL_SMARTCARD_ is send to the driver. Arguments - SmartcardExtension is a pointer on the SmartCardExtension structure of the current device. Return Value: STATUS_SUCCESS - We could execute the request. STATUS_BUFFER_TOO_SMALL - The output buffer is to small. STATUS_NOT_SUPPORTED - We could not support the Ioctl specified. --*/ { PREADER_EXTENSION pReaderExtension = SmartcardExtension->ReaderExtension; UCHAR To; UCHAR Vo[GPR_BUFFER_SIZE]; USHORT Lo; USHORT BufferInLen = 0; NTSTATUS lStatus=STATUS_SUCCESS; PREADER_EXTENSION pReader; ASSERT(SmartcardExtension != NULL); // Set the reply buffer length to 0. *SmartcardExtension->IoRequest.Information = 0; pReader = SmartcardExtension->ReaderExtension; waitForIdleAndBlock(pReader); //Switch for the different IOCTL: switch(SmartcardExtension->MajorIoControlCode) { case IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE: case IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE: SpecificTag( SmartcardExtension, (ULONG) SmartcardExtension->MajorIoControlCode, (ULONG) SmartcardExtension->IoRequest.RequestBufferLength, (PUCHAR) SmartcardExtension->IoRequest.RequestBuffer, (ULONG) SmartcardExtension->IoRequest.ReplyBufferLength, (PUCHAR) SmartcardExtension->IoRequest.ReplyBuffer, (PULONG) SmartcardExtension->IoRequest.Information ); break; // IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE: // Translate the buffer to TLV and send it to the reader. case IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE: if(SmartcardExtension->IoRequest.ReplyBufferLength < 3) { setIdle(pReader); return(STATUS_INVALID_BUFFER_SIZE); } BufferInLen = (SmartcardExtension->IoRequest.RequestBuffer[2]*0x100) + SmartcardExtension->IoRequest.RequestBuffer[1]; if( (ULONG) BufferInLen > (SmartcardExtension->IoRequest.ReplyBufferLength - 3)) { setIdle(pReader); return(STATUS_INVALID_BUFFER_SIZE); } Lo = GPR_BUFFER_SIZE; To = 0x00; Vo[0] = 0x00; lStatus = GprllTLVExchange( pReaderExtension, (const BYTE) SmartcardExtension->IoRequest.RequestBuffer[0], (const USHORT) BufferInLen, (const BYTE *) &(SmartcardExtension->IoRequest.RequestBuffer[3]), &To, &Lo, Vo ); if (lStatus != STATUS_SUCCESS) { setIdle(pReader); return (lStatus); } // Check if there is enough space in the reply buffer if((ULONG)(Lo+3) > SmartcardExtension->IoRequest.ReplyBufferLength) { setIdle(pReader); return(STATUS_INVALID_BUFFER_SIZE); } else { ASSERT(SmartcardExtension->IoRequest.ReplyBuffer != 0); SmartcardExtension->IoRequest.ReplyBuffer[0] = To; SmartcardExtension->IoRequest.ReplyBuffer[1] = LOBYTE(Lo); SmartcardExtension->IoRequest.ReplyBuffer[2] = HIBYTE(Lo); memcpy((SmartcardExtension->IoRequest.ReplyBuffer)+3,Vo,Lo); *(SmartcardExtension->IoRequest.Information) = (DWORD) (Lo + 3); setIdle(pReader); return(STATUS_SUCCESS); } // // For IOCTL_SMARTCARD_VENDOR_SWITCH_SPEED // Call the SwitchSpeed function // case IOCTL_SMARTCARD_VENDOR_SWITCH_SPEED: lStatus = SwitchSpeed( SmartcardExtension, (ULONG) SmartcardExtension->IoRequest.RequestBufferLength, (PUCHAR) SmartcardExtension->IoRequest.RequestBuffer, (ULONG) SmartcardExtension->IoRequest.ReplyBufferLength, (PUCHAR) SmartcardExtension->IoRequest.ReplyBuffer, (PULONG) SmartcardExtension->IoRequest.Information ); break; default: setIdle(pReader); return STATUS_NOT_SUPPORTED; } setIdle(pReader); return lStatus; } NTSTATUS GprCbSetupCardTracking( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ Routine Description: This function is called by the Smart card library when an IOCTL_SMARTCARD_IS_PRESENT or IOCTL_SMARTCARD_IS_ABSENT occurs. Arguments: SmartcardExtension - is a pointer on the SmartCardExtension structure of the current device. Return Value: STATUS_PENDING - The request is in a pending mode. --*/ { NTSTATUS NTStatus = STATUS_PENDING; POS_DEP_DATA pOS = NULL; KIRQL oldIrql; ASSERT(SmartcardExtension != NULL); // //Initialize // pOS = SmartcardExtension->OsData; // //Set cancel routine for the notification IRP. // IoAcquireCancelSpinLock(&oldIrql); IoSetCancelRoutine( pOS->NotificationIrp, GprCancelEventWait ); IoReleaseCancelSpinLock(oldIrql); NTStatus = STATUS_PENDING; return (NTStatus); }